Transaction Hash:
Block:
18894895 at Dec-30-2023 12:50:23 AM +UTC
Transaction Fee:
0.005117058701532144 ETH
$9.79
Gas Used:
314,152 Gas / 16.288480422 Gwei
Emitted Events:
| 151 |
eNear.ConsumedProof( _receiptId=854096901C8855C25AA309BA114D5E6F4B536181C2504848DB8EE5BCC58DD746 )
|
| 152 |
eNear.Transfer( from=0x0000000000000000000000000000000000000000, to=[Sender] 0x324594bdd150e359a2492c2e72533d67b6d1db85, value=246000000000000000000000000 )
|
| 153 |
eNear.NearToEthTransferFinalised( amount=246000000000000000000000000, recipient=[Sender] 0x324594bdd150e359a2492c2e72533d67b6d1db85 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x324594Bd...7b6D1dB85 |
107.629675774289409174 Eth
Nonce: 390
|
107.62455871558787703 Eth
Nonce: 391
| 0.005117058701532144 | ||
| 0x85F17Cf9...bD4B9f6a4 | |||||
|
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 13.735463057225233672 Eth | 13.735494472425233672 Eth | 0.0000314152 |
Execution Trace
eNear.finaliseNearToEthTransfer( proofData=0x040000009B484B3B0AF0BF63B510D6FB270C3B8C720C2A9A8F7FA2DA85785E820B4C1444012EE0A2B5DD3CC51F1A8B6C0724544B0C71E1A1F6CA99D60D2FC838C6FF8AC2B80097D48110DFA9AC7BF9372F8C8DFE9C6BDA1B5FB57D10F811E97C2AA4D7AF3F2E011AC44CE3520650BBD0BB4F3818D6EB4BDD5B68FBF6FE2CF66CAD92ED74F3FF5C002792D21308C1D9FA6EBAEE0BC5EA97BC44920F7C6D22A8712257E6CEB65045761DA07F39EA2D1A606594C61C5EB856A1F6F8F1087622448F845C5D55D71102740000000001000000854096901C8855C25AA309BA114D5E6F4B536181C2504848DB8EE5BCC58DD74610FBB1129E0200000010F903AB4CF2990F000000000000000B000000652D6E6561722E6E656172022500000000000000B658ECB8B8867CCB0000000000324594BDD150E359A2492C2E72533D67B6D1DB8502000000A76E094F6D4A01E6E1988071A3E2D0E474856ADF07EF5F040E51DDCF6A6F180101EB1319D7EE76EE4FAEBE65330345AC47A3F09DEAC3816E4C2D84C46D88E2F52100C958CEFB246970C467481374B08BC009032B8DB9304970BE5BC14492509F4C3A9F5673CC47680221925FE9F9BCB762D91FCE7BE69AAEC730D1366118DA30A906E7DF0D060000000034AA3210244E8E9B12F1ED8B9F977C79A89B88332945F461C83310C8DFF0CECBA32035A4844650D56479FB4FEEF009F390EA836B0EB2D3D26208F000E133280B9634E71ADB75478B74622B8F2374A7ACC08345855B345531F839A7D86C48AC6AE6199D0E4B1CABB4EB07A907769AEB6EABBD1CB7A04271DE8263E0BA7D79ED49048F9E6096B386171E2E9B784B27E69C7D3A19AB77A68A5FD821EB1AD862B4B723D6880DE8D77AC41BF835EBC8ACAF8934C7A8EF2654760D28604C824C86C044D6B78F9390DBFC9A1A000000C958CEFB246970C467481374B08BC009032B8DB9304970BE5BC14492509F4C3A0098E624597AE2754DDA9C4055B224E14CBC7EC8B983893F95FFC551AF289B155901869E87DC6A4D2AC9FD95C9AAFF291761327F8CD818E87212A0E1F55557AFB646010BA183D5E50A732D2B738831228E3779F911E45247055BEDF84C3DA2DF3EEB5601D96C00EAE74452F609706E39F5ED0AEBAE6828073AC2487DF71492D10B07F5FA00CC74A9749115AFED15EAD3221B837BD6621DC3750CD11934A38745082A335BEA0194A054D11C65F6749B46F7C5D7DCDF5CB3ED0014B2A852E89054FE48EB50D6E40062A3600EB24A5F7801A2E5749DAFBAED0F517BE9BDBFAF05C880BAF354FE495F016993966D521E3A284FD798A2079FF078B25CFF52B52A5F5227915A7F5EC998AD00126724B88F90CC7E4203D4FE3E4DFD47396A556494DD3CABF36102125B8996C901FEFCA491CC538FEA0A50FA8744EE03117139CB0D89192CF3772139790B04C33B013767495D76D7D63AD25DE81D32EAF0AD667B58FCA68228F614CECCE4B878F21A012FA6C573FE53C6906A19ABDFBCF1FFF5E5AFA2E5FF2224227DECC7972F7F587201A743AF799571EE2EDB7D672DFFA9A800821933554CAE16AD0F6BDD63D3556B990085DD4713BED410F1529E0783ADEE30201E7147949674A02E3F5B72ACEAB3D09D0060EA375F077DB92A3D850433AA90F86DEF6473D30471E5115ACDBED5AAA8729301CE61BEC753F0C2CFBDDF24D7CA7746C005203764A41CD596142D74E90C2B5F6001458B66EC0E6FDBEB0E468ADE434759EBE03964BE02C7066554DAE460362E067D01E872A35E49FAF05AB92AC3587CF43FE31CBABD69AF797C9F655BD45A6BF6024E0018423638584FC568F497B81094124A093B3DD30D0D69B4FC3AF2F45B94B0FD0101FC3F35291D237F1DCB65EE124A6B963622729408C9A4CD1E5872664A5285FA74002E9669401DC598426BD47F45918D67ACBBDEBD20CB062F78BA848E0BA7F53EC20003A84D735713A0E69AA78A3234E5BE2A21BCA7E0DF9B7AD1B8DCD1D42787A1BF00C31B19250C1479C0F6A372C1464ADBE5B48F8114224902E92F2FBE643160BB8F01129E063AA421F88A829540D9A00AEA80433A755EFAFDFDA35D6760F3E270F25500124BB839A5B9C44856054C6D80BD5229AC2B40FA8A0CD44911629F295B11F08200, proofBlockHeight=109102798 )
NearProver.proveOutcome( proofData=0x040000009B484B3B0AF0BF63B510D6FB270C3B8C720C2A9A8F7FA2DA85785E820B4C1444012EE0A2B5DD3CC51F1A8B6C0724544B0C71E1A1F6CA99D60D2FC838C6FF8AC2B80097D48110DFA9AC7BF9372F8C8DFE9C6BDA1B5FB57D10F811E97C2AA4D7AF3F2E011AC44CE3520650BBD0BB4F3818D6EB4BDD5B68FBF6FE2CF66CAD92ED74F3FF5C002792D21308C1D9FA6EBAEE0BC5EA97BC44920F7C6D22A8712257E6CEB65045761DA07F39EA2D1A606594C61C5EB856A1F6F8F1087622448F845C5D55D71102740000000001000000854096901C8855C25AA309BA114D5E6F4B536181C2504848DB8EE5BCC58DD74610FBB1129E0200000010F903AB4CF2990F000000000000000B000000652D6E6561722E6E656172022500000000000000B658ECB8B8867CCB0000000000324594BDD150E359A2492C2E72533D67B6D1DB8502000000A76E094F6D4A01E6E1988071A3E2D0E474856ADF07EF5F040E51DDCF6A6F180101EB1319D7EE76EE4FAEBE65330345AC47A3F09DEAC3816E4C2D84C46D88E2F52100C958CEFB246970C467481374B08BC009032B8DB9304970BE5BC14492509F4C3A9F5673CC47680221925FE9F9BCB762D91FCE7BE69AAEC730D1366118DA30A906E7DF0D060000000034AA3210244E8E9B12F1ED8B9F977C79A89B88332945F461C83310C8DFF0CECBA32035A4844650D56479FB4FEEF009F390EA836B0EB2D3D26208F000E133280B9634E71ADB75478B74622B8F2374A7ACC08345855B345531F839A7D86C48AC6AE6199D0E4B1CABB4EB07A907769AEB6EABBD1CB7A04271DE8263E0BA7D79ED49048F9E6096B386171E2E9B784B27E69C7D3A19AB77A68A5FD821EB1AD862B4B723D6880DE8D77AC41BF835EBC8ACAF8934C7A8EF2654760D28604C824C86C044D6B78F9390DBFC9A1A000000C958CEFB246970C467481374B08BC009032B8DB9304970BE5BC14492509F4C3A0098E624597AE2754DDA9C4055B224E14CBC7EC8B983893F95FFC551AF289B155901869E87DC6A4D2AC9FD95C9AAFF291761327F8CD818E87212A0E1F55557AFB646010BA183D5E50A732D2B738831228E3779F911E45247055BEDF84C3DA2DF3EEB5601D96C00EAE74452F609706E39F5ED0AEBAE6828073AC2487DF71492D10B07F5FA00CC74A9749115AFED15EAD3221B837BD6621DC3750CD11934A38745082A335BEA0194A054D11C65F6749B46F7C5D7DCDF5CB3ED0014B2A852E89054FE48EB50D6E40062A3600EB24A5F7801A2E5749DAFBAED0F517BE9BDBFAF05C880BAF354FE495F016993966D521E3A284FD798A2079FF078B25CFF52B52A5F5227915A7F5EC998AD00126724B88F90CC7E4203D4FE3E4DFD47396A556494DD3CABF36102125B8996C901FEFCA491CC538FEA0A50FA8744EE03117139CB0D89192CF3772139790B04C33B013767495D76D7D63AD25DE81D32EAF0AD667B58FCA68228F614CECCE4B878F21A012FA6C573FE53C6906A19ABDFBCF1FFF5E5AFA2E5FF2224227DECC7972F7F587201A743AF799571EE2EDB7D672DFFA9A800821933554CAE16AD0F6BDD63D3556B990085DD4713BED410F1529E0783ADEE30201E7147949674A02E3F5B72ACEAB3D09D0060EA375F077DB92A3D850433AA90F86DEF6473D30471E5115ACDBED5AAA8729301CE61BEC753F0C2CFBDDF24D7CA7746C005203764A41CD596142D74E90C2B5F6001458B66EC0E6FDBEB0E468ADE434759EBE03964BE02C7066554DAE460362E067D01E872A35E49FAF05AB92AC3587CF43FE31CBABD69AF797C9F655BD45A6BF6024E0018423638584FC568F497B81094124A093B3DD30D0D69B4FC3AF2F45B94B0FD0101FC3F35291D237F1DCB65EE124A6B963622729408C9A4CD1E5872664A5285FA74002E9669401DC598426BD47F45918D67ACBBDEBD20CB062F78BA848E0BA7F53EC20003A84D735713A0E69AA78A3234E5BE2A21BCA7E0DF9B7AD1B8DCD1D42787A1BF00C31B19250C1479C0F6A372C1464ADBE5B48F8114224902E92F2FBE643160BB8F01129E063AA421F88A829540D9A00AEA80433A755EFAFDFDA35D6760F3E270F25500124BB839A5B9C44856054C6D80BD5229AC2B40FA8A0CD44911629F295B11F08200, blockHeight=109102798 ) => ( True )-
Null: 0x000...002.01000000( )
-
Null: 0x000...002.02000000( )
-
Null: 0x000...002.e7df0d06( )
-
Null: 0x000...002.5a72a7f7( )
-
Null: 0x000...002.47fb831f( )
-
Null: 0x000...002.66a2c5ff( )
-
Null: 0x000...002.2ee0a2b5( )
-
Null: 0x000...002.472fc840( )
-
Null: 0x000...002.1ac44ce3( )
-
Null: 0x000...002.d2c76f0e( )
-
Null: 0x000...002.3ace4c85( )
-
Null: 0x000...002.eb1319d7( )
-
NearBridge.blockMerkleRoots( height=109102798 ) => ( res=BDCD8C698D888DDCC56E0E34503F8B958807AAEC73869A3C1FA86351BD05D737 ) -
Null: 0x000...002.c958cefb( )
-
Null: 0x000...002.c7e376be( )
-
Null: 0x000...002.8d97a235( )
-
Null: 0x000...002.28638247( )
-
Null: 0x000...002.d96c00ea( )
-
Null: 0x000...002.723e26dc( )
-
Null: 0x000...002.94a054d1( )
-
Null: 0x000...002.a36120e9( )
-
Null: 0x000...002.6993966d( )
-
Null: 0x000...002.3e378e1c( )
-
Null: 0x000...002.93a9e8f7( )
-
Null: 0x000...002.5ab780e5( )
-
Null: 0x000...002.e093c223( )
-
Null: 0x000...002.a743af79( )
-
Null: 0x000...002.85dd4713( )
-
Null: 0x000...002.ba548771( )
-
Null: 0x000...002.d31db069( )
-
Null: 0x000...002.085d54aa( )
-
Null: 0x000...002.e872a35e( )
-
Null: 0x000...002.0d663317( )
-
Null: 0x000...002.fc3f3529( )
-
Null: 0x000...002.2e966940( )
-
Null: 0x000...002.03a84d73( )
-
Null: 0x000...002.dc19deea( )
-
Null: 0x000...002.129e063a( )
-
Null: 0x000...002.124bb839( )
-
-
Null: 0x000...002.01000000( )
-
Null: 0x000...002.02000000( )
-
Null: 0x000...002.e7df0d06( )
-
Null: 0x000...002.5a72a7f7( )
-
Null: 0x000...002.47fb831f( )
finaliseNearToEthTransfer[eNear (ln:43)]
_parseAndConsumeProof[eNear (ln:45)]_decodeBridgeResult[eNear (ln:46)]from[eNear (ln:56)]Data[Borsh (ln:226)]
decodeU8[eNear (ln:57)]decodeU128[eNear (ln:59)]decodeBytes20[eNear (ln:60)]
_mint[eNear (ln:47)]NearToEthTransferFinalised[eNear (ln:48)]
File 1 of 3: eNear
File 2 of 3: NearProver
File 3 of 3: NearBridge
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "rainbow-bridge/contracts/eth/nearprover/contracts/ProofDecoder.sol";
import "rainbow-bridge/contracts/eth/nearbridge/contracts/Borsh.sol";
import "rainbow-bridge/contracts/eth/nearbridge/contracts/AdminControlled.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Bridge, INearProver } from "./Bridge.sol";
contract eNear is ERC20, Bridge, AdminControlled {
uint constant PAUSE_FINALISE_FROM_NEAR = 1 << 0;
uint constant PAUSE_TRANSFER_TO_NEAR = 1 << 1;
event TransferToNearInitiated (
address indexed sender,
uint256 amount,
string accountId
);
event NearToEthTransferFinalised (
uint128 amount,
address indexed recipient
);
struct BridgeResult {
uint128 amount;
address recipient;
}
/// @param _tokenName Name given to the token (can be admin updated)
/// @param _tokenSymbol Symbol given to the token (can be admin updated)
/// @param _nearConnector Near account ID of the near connector bridge
/// @param _prover Address of the prover contract on ETH
/// @param _minBlockAcceptanceHeight The contract will accept proofs from this block onwards
/// @param _admin Address that can make admin changes to the contract
/// @param _pausedFlags Flag settings which controls whether certain methods are paused or active
constructor(
string memory _tokenName,
string memory _tokenSymbol,
bytes memory _nearConnector,
INearProver _prover,
uint64 _minBlockAcceptanceHeight,
address _admin,
uint256 _pausedFlags
) public ERC20(_tokenName, _tokenSymbol) AdminControlled(_admin, _pausedFlags) Bridge(_prover, _nearConnector, _minBlockAcceptanceHeight) {
// Match yocto Near
_setupDecimals(24);
}
function finaliseNearToEthTransfer(bytes memory proofData, uint64 proofBlockHeight)
external pausable (PAUSE_FINALISE_FROM_NEAR) {
ProofDecoder.ExecutionStatus memory status = _parseAndConsumeProof(proofData, proofBlockHeight);
BridgeResult memory result = _decodeBridgeResult(status.successValue);
_mint(result.recipient, result.amount);
emit NearToEthTransferFinalised(result.amount, result.recipient);
}
function transferToNear(uint256 _amount, string memory _nearReceiverAccountId)
external pausable (PAUSE_TRANSFER_TO_NEAR) {
_burn(msg.sender, _amount);
emit TransferToNearInitiated(msg.sender, _amount, _nearReceiverAccountId);
}
function _decodeBridgeResult(bytes memory data) internal pure returns(BridgeResult memory result) {
Borsh.Data memory borshData = Borsh.from(data);
uint8 flag = borshData.decodeU8();
require(flag == 0, "ERR_NOT_WITHDRAW_RESULT");
result.amount = borshData.decodeU128();
bytes20 recipient = borshData.decodeBytes20();
result.recipient = address(uint160(recipient));
}
}
pragma solidity ^0.6;
import "../../nearbridge/contracts/Borsh.sol";
import "../../nearbridge/contracts/NearDecoder.sol";
library ProofDecoder {
using Borsh for Borsh.Data;
using ProofDecoder for Borsh.Data;
using NearDecoder for Borsh.Data;
struct FullOutcomeProof {
ExecutionOutcomeWithIdAndProof outcome_proof;
MerklePath outcome_root_proof; // TODO: now empty array
BlockHeaderLight block_header_lite;
MerklePath block_proof;
}
function decodeFullOutcomeProof(Borsh.Data memory data) internal view returns (FullOutcomeProof memory proof) {
proof.outcome_proof = data.decodeExecutionOutcomeWithIdAndProof();
proof.outcome_root_proof = data.decodeMerklePath();
proof.block_header_lite = data.decodeBlockHeaderLight();
proof.block_proof = data.decodeMerklePath();
}
struct BlockHeaderLight {
bytes32 prev_block_hash;
bytes32 inner_rest_hash;
NearDecoder.BlockHeaderInnerLite inner_lite;
bytes32 hash; // Computable
}
function decodeBlockHeaderLight(Borsh.Data memory data) internal view returns (BlockHeaderLight memory header) {
header.prev_block_hash = data.decodeBytes32();
header.inner_rest_hash = data.decodeBytes32();
header.inner_lite = data.decodeBlockHeaderInnerLite();
header.hash = sha256(
abi.encodePacked(
sha256(abi.encodePacked(header.inner_lite.hash, header.inner_rest_hash)),
header.prev_block_hash
)
);
}
struct ExecutionStatus {
uint8 enumIndex;
bool unknown;
bool failed;
bytes successValue; /// The final action succeeded and returned some value or an empty vec.
bytes32 successReceiptId; /// The final action of the receipt returned a promise or the signed
/// transaction was converted to a receipt. Contains the receipt_id of the generated receipt.
}
function decodeExecutionStatus(Borsh.Data memory data)
internal
pure
returns (ExecutionStatus memory executionStatus)
{
executionStatus.enumIndex = data.decodeU8();
if (executionStatus.enumIndex == 0) {
executionStatus.unknown = true;
} else if (executionStatus.enumIndex == 1) {
//revert("NearDecoder: decodeExecutionStatus failure case not implemented yet");
// Can avoid revert since ExecutionStatus is latest field in all parent structures
executionStatus.failed = true;
} else if (executionStatus.enumIndex == 2) {
executionStatus.successValue = data.decodeBytes();
} else if (executionStatus.enumIndex == 3) {
executionStatus.successReceiptId = data.decodeBytes32();
} else {
revert("NearDecoder: decodeExecutionStatus index out of range");
}
}
struct ExecutionOutcome {
bytes[] logs; /// Logs from this transaction or receipt.
bytes32[] receipt_ids; /// Receipt IDs generated by this transaction or receipt.
uint64 gas_burnt; /// The amount of the gas burnt by the given transaction or receipt.
uint128 tokens_burnt; /// The total number of the tokens burnt by the given transaction or receipt.
bytes executor_id; /// Hash of the transaction or receipt id that produced this outcome.
ExecutionStatus status; /// Execution status. Contains the result in case of successful execution.
bytes32[] merkelization_hashes;
}
function decodeExecutionOutcome(Borsh.Data memory data) internal view returns (ExecutionOutcome memory outcome) {
outcome.logs = new bytes[](data.decodeU32());
for (uint i = 0; i < outcome.logs.length; i++) {
outcome.logs[i] = data.decodeBytes();
}
uint256 start = data.offset;
outcome.receipt_ids = new bytes32[](data.decodeU32());
for (uint i = 0; i < outcome.receipt_ids.length; i++) {
outcome.receipt_ids[i] = data.decodeBytes32();
}
outcome.gas_burnt = data.decodeU64();
outcome.tokens_burnt = data.decodeU128();
outcome.executor_id = data.decodeBytes();
outcome.status = data.decodeExecutionStatus();
uint256 stop = data.offset;
outcome.merkelization_hashes = new bytes32[](1 + outcome.logs.length);
data.offset = start;
outcome.merkelization_hashes[0] = data.peekSha256(stop - start);
data.offset = stop;
for (uint i = 0; i < outcome.logs.length; i++) {
outcome.merkelization_hashes[i + 1] = sha256(outcome.logs[i]);
}
}
struct ExecutionOutcomeWithId {
bytes32 id; /// The transaction hash or the receipt ID.
ExecutionOutcome outcome;
bytes32 hash;
}
function decodeExecutionOutcomeWithId(Borsh.Data memory data)
internal
view
returns (ExecutionOutcomeWithId memory outcome)
{
outcome.id = data.decodeBytes32();
outcome.outcome = data.decodeExecutionOutcome();
uint256 len = 1 + outcome.outcome.merkelization_hashes.length;
outcome.hash = sha256(
abi.encodePacked(
uint8((len >> 0) & 0xFF),
uint8((len >> 8) & 0xFF),
uint8((len >> 16) & 0xFF),
uint8((len >> 24) & 0xFF),
outcome.id,
outcome.outcome.merkelization_hashes
)
);
}
struct MerklePathItem {
bytes32 hash;
uint8 direction; // 0 = left, 1 = right
}
function decodeMerklePathItem(Borsh.Data memory data) internal pure returns (MerklePathItem memory item) {
item.hash = data.decodeBytes32();
item.direction = data.decodeU8();
require(item.direction < 2, "ProofDecoder: MerklePathItem direction should be 0 or 1");
}
struct MerklePath {
MerklePathItem[] items;
}
function decodeMerklePath(Borsh.Data memory data) internal pure returns (MerklePath memory path) {
path.items = new MerklePathItem[](data.decodeU32());
for (uint i = 0; i < path.items.length; i++) {
path.items[i] = data.decodeMerklePathItem();
}
}
struct ExecutionOutcomeWithIdAndProof {
MerklePath proof;
bytes32 block_hash;
ExecutionOutcomeWithId outcome_with_id;
}
function decodeExecutionOutcomeWithIdAndProof(Borsh.Data memory data)
internal
view
returns (ExecutionOutcomeWithIdAndProof memory outcome)
{
outcome.proof = data.decodeMerklePath();
outcome.block_hash = data.decodeBytes32();
outcome.outcome_with_id = data.decodeExecutionOutcomeWithId();
}
}
pragma solidity ^0.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
library Borsh {
using SafeMath for uint256;
struct Data {
uint256 offset;
bytes raw;
}
function from(bytes memory data) internal pure returns (Data memory) {
return Data({offset: 0, raw: data});
}
modifier shift(Data memory data, uint256 size) {
require(data.raw.length >= data.offset + size, "Borsh: Out of range");
_;
data.offset += size;
}
function finished(Data memory data) internal pure returns (bool) {
return data.offset == data.raw.length;
}
function peekKeccak256(Data memory data, uint256 length) internal pure returns (bytes32 res) {
return bytesKeccak256(data.raw, data.offset, length);
}
function bytesKeccak256(
bytes memory ptr,
uint256 offset,
uint256 length
) internal pure returns (bytes32 res) {
// solium-disable-next-line security/no-inline-assembly
assembly {
res := keccak256(add(add(ptr, 32), offset), length)
}
}
function peekSha256(Data memory data, uint256 length) internal view returns (bytes32) {
return bytesSha256(data.raw, data.offset, length);
}
function bytesSha256(
bytes memory ptr,
uint256 offset,
uint256 length
) internal view returns (bytes32) {
bytes32[1] memory result;
// solium-disable-next-line security/no-inline-assembly
assembly {
pop(staticcall(gas(), 0x02, add(add(ptr, 32), offset), length, result, 32))
}
return result[0];
}
function decodeU8(Data memory data) internal pure shift(data, 1) returns (uint8 value) {
value = uint8(data.raw[data.offset]);
}
function decodeI8(Data memory data) internal pure shift(data, 1) returns (int8 value) {
value = int8(data.raw[data.offset]);
}
function decodeU16(Data memory data) internal pure returns (uint16 value) {
value = uint16(decodeU8(data));
value |= (uint16(decodeU8(data)) << 8);
}
function decodeI16(Data memory data) internal pure returns (int16 value) {
value = int16(decodeI8(data));
value |= (int16(decodeI8(data)) << 8);
}
function decodeU32(Data memory data) internal pure returns (uint32 value) {
value = uint32(decodeU16(data));
value |= (uint32(decodeU16(data)) << 16);
}
function decodeI32(Data memory data) internal pure returns (int32 value) {
value = int32(decodeI16(data));
value |= (int32(decodeI16(data)) << 16);
}
function decodeU64(Data memory data) internal pure returns (uint64 value) {
value = uint64(decodeU32(data));
value |= (uint64(decodeU32(data)) << 32);
}
function decodeI64(Data memory data) internal pure returns (int64 value) {
value = int64(decodeI32(data));
value |= (int64(decodeI32(data)) << 32);
}
function decodeU128(Data memory data) internal pure returns (uint128 value) {
value = uint128(decodeU64(data));
value |= (uint128(decodeU64(data)) << 64);
}
function decodeI128(Data memory data) internal pure returns (int128 value) {
value = int128(decodeI64(data));
value |= (int128(decodeI64(data)) << 64);
}
function decodeU256(Data memory data) internal pure returns (uint256 value) {
value = uint256(decodeU128(data));
value |= (uint256(decodeU128(data)) << 128);
}
function decodeI256(Data memory data) internal pure returns (int256 value) {
value = int256(decodeI128(data));
value |= (int256(decodeI128(data)) << 128);
}
function decodeBool(Data memory data) internal pure returns (bool value) {
value = (decodeU8(data) != 0);
}
function decodeBytes(Data memory data) internal pure returns (bytes memory value) {
value = new bytes(decodeU32(data));
for (uint i = 0; i < value.length; i++) {
value[i] = byte(decodeU8(data));
}
}
function decodeBytes32(Data memory data) internal pure shift(data, 32) returns (bytes32 value) {
bytes memory raw = data.raw;
uint256 offset = data.offset;
// solium-disable-next-line security/no-inline-assembly
assembly {
value := mload(add(add(raw, 32), offset))
}
}
function decodeBytes20(Data memory data) internal pure returns (bytes20 value) {
for (uint i = 0; i < 20; i++) {
value |= bytes20(byte(decodeU8(data)) & 0xFF) >> (i * 8);
}
}
// Public key
struct SECP256K1PublicKey {
uint256 x;
uint256 y;
}
function decodeSECP256K1PublicKey(Borsh.Data memory data) internal pure returns (SECP256K1PublicKey memory key) {
key.x = decodeU256(data);
key.y = decodeU256(data);
}
struct ED25519PublicKey {
bytes32 xy;
}
function decodeED25519PublicKey(Borsh.Data memory data) internal pure returns (ED25519PublicKey memory key) {
key.xy = decodeBytes32(data);
}
// Signature
struct SECP256K1Signature {
bytes32 r;
bytes32 s;
uint8 v;
}
function decodeSECP256K1Signature(Borsh.Data memory data) internal pure returns (SECP256K1Signature memory sig) {
sig.r = decodeBytes32(data);
sig.s = decodeBytes32(data);
sig.v = decodeU8(data);
}
struct ED25519Signature {
bytes32[2] rs;
}
function decodeED25519Signature(Borsh.Data memory data) internal pure returns (ED25519Signature memory sig) {
sig.rs[0] = decodeBytes32(data);
sig.rs[1] = decodeBytes32(data);
}
}
pragma solidity ^0.6;
contract AdminControlled {
address public admin;
uint public paused;
constructor(address _admin, uint flags) public {
admin = _admin;
// Add the possibility to set pause flags on the initialization
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 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;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../../utils/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with
* a default value of 18.
*
* To select a different value for {decimals}, use {_setupDecimals}.
*
* All three of these values are immutable: they can only be set once during
* construction.
*/
constructor (string memory name_, string memory symbol_) public {
_name = name_;
_symbol = symbol_;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Sets {decimals} to a value other than the default one of 18.
*
* WARNING: This function should only be called from the constructor. Most
* applications that interact with token contracts will not expect
* {decimals} to ever change, and may work incorrectly if it does.
*/
function _setupDecimals(uint8 decimals_) internal virtual {
_decimals = decimals_;
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "rainbow-bridge/contracts/eth/nearprover/contracts/INearProver.sol";
import "rainbow-bridge/contracts/eth/nearprover/contracts/ProofDecoder.sol";
import "rainbow-bridge/contracts/eth/nearbridge/contracts/Borsh.sol";
contract Bridge {
using Borsh for Borsh.Data;
using ProofDecoder for Borsh.Data;
event ConsumedProof(bytes32 indexed _receiptId);
INearProver public prover;
bytes public nearConnector;
/// Proofs from blocks that are below the acceptance height will be rejected.
// If `minBlockAcceptanceHeight` value is zero - proofs from block with any height are accepted.
uint64 public minBlockAcceptanceHeight;
// OutcomeRecieptId -> Used
mapping(bytes32 => bool) public usedProofs;
constructor(INearProver _prover, bytes memory _nearConnector, uint64 _minBlockAcceptanceHeight) public {
prover = _prover;
nearConnector = _nearConnector;
minBlockAcceptanceHeight = _minBlockAcceptanceHeight;
}
/// Parses the provided proof and consumes it if it's not already used.
/// The consumed event cannot be reused for future calls.
function _parseAndConsumeProof(bytes memory proofData, uint64 proofBlockHeight)
internal
returns (ProofDecoder.ExecutionStatus memory result)
{
require(prover.proveOutcome(proofData, proofBlockHeight), "Proof should be valid");
// Unpack the proof and extract the execution outcome.
Borsh.Data memory borshData = Borsh.from(proofData);
ProofDecoder.FullOutcomeProof memory fullOutcomeProof = borshData.decodeFullOutcomeProof();
require(
fullOutcomeProof.block_header_lite.inner_lite.height >= minBlockAcceptanceHeight,
"Proof is from the ancient block"
);
require(borshData.finished(), "Argument should be exact borsh serialization");
bytes32 receiptId = fullOutcomeProof.outcome_proof.outcome_with_id.outcome.receipt_ids[0];
require(!usedProofs[receiptId], "The burn event proof cannot be reused");
usedProofs[receiptId] = true;
require(keccak256(fullOutcomeProof.outcome_proof.outcome_with_id.outcome.executor_id)
== keccak256(nearConnector),
"Can only unlock tokens from the linked proof producer on Near blockchain");
result = fullOutcomeProof.outcome_proof.outcome_with_id.outcome.status;
require(!result.failed, "Cannot use failed execution outcome for unlocking the tokens");
require(!result.unknown, "Cannot use unknown execution outcome for unlocking the tokens");
emit ConsumedProof(receiptId);
}
}
pragma solidity ^0.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./Borsh.sol";
library NearDecoder {
using Borsh for Borsh.Data;
using NearDecoder for Borsh.Data;
struct PublicKey {
uint8 enumIndex;
Borsh.ED25519PublicKey ed25519;
Borsh.SECP256K1PublicKey secp256k1;
}
function decodePublicKey(Borsh.Data memory data) internal pure returns (PublicKey memory key) {
key.enumIndex = data.decodeU8();
if (key.enumIndex == 0) {
key.ed25519 = data.decodeED25519PublicKey();
} else if (key.enumIndex == 1) {
key.secp256k1 = data.decodeSECP256K1PublicKey();
} else {
revert("NearBridge: Only ED25519 and SECP256K1 public keys are supported");
}
}
struct ValidatorStake {
string account_id;
PublicKey public_key;
uint128 stake;
}
function decodeValidatorStake(Borsh.Data memory data) internal pure returns (ValidatorStake memory validatorStake) {
validatorStake.account_id = string(data.decodeBytes());
validatorStake.public_key = data.decodePublicKey();
validatorStake.stake = data.decodeU128();
}
struct OptionalValidatorStakes {
bool none;
ValidatorStake[] validatorStakes;
bytes32 hash; // Additional computable element
}
function decodeOptionalValidatorStakes(Borsh.Data memory data)
internal
view
returns (OptionalValidatorStakes memory stakes)
{
stakes.none = (data.decodeU8() == 0);
if (!stakes.none) {
uint256 start = data.offset;
stakes.validatorStakes = new ValidatorStake[](data.decodeU32());
for (uint i = 0; i < stakes.validatorStakes.length; i++) {
stakes.validatorStakes[i] = data.decodeValidatorStake();
}
uint256 stop = data.offset;
data.offset = start;
stakes.hash = data.peekSha256(stop - start);
data.offset = stop;
}
}
struct Signature {
uint8 enumIndex;
Borsh.ED25519Signature ed25519;
Borsh.SECP256K1Signature secp256k1;
}
function decodeSignature(Borsh.Data memory data) internal pure returns (Signature memory sig) {
sig.enumIndex = data.decodeU8();
if (sig.enumIndex == 0) {
sig.ed25519 = data.decodeED25519Signature();
} else if (sig.enumIndex == 1) {
sig.secp256k1 = data.decodeSECP256K1Signature();
} else {
revert("NearBridge: Only ED25519 and SECP256K1 signatures are supported");
}
}
struct OptionalSignature {
bool none;
Signature signature;
}
function decodeOptionalSignature(Borsh.Data memory data) internal pure returns (OptionalSignature memory sig) {
sig.none = (data.decodeU8() == 0);
if (!sig.none) {
sig.signature = data.decodeSignature();
}
}
struct LightClientBlock {
bytes32 prev_block_hash;
bytes32 next_block_inner_hash;
BlockHeaderInnerLite inner_lite;
bytes32 inner_rest_hash;
OptionalValidatorStakes next_bps;
OptionalSignature[] approvals_after_next;
bytes32 hash;
bytes32 next_hash;
}
struct InitialValidators {
ValidatorStake[] validator_stakes;
}
function decodeInitialValidators(Borsh.Data memory data)
internal
view
returns (InitialValidators memory validators)
{
validators.validator_stakes = new ValidatorStake[](data.decodeU32());
for (uint i = 0; i < validators.validator_stakes.length; i++) {
validators.validator_stakes[i] = data.decodeValidatorStake();
}
}
function decodeLightClientBlock(Borsh.Data memory data) internal view returns (LightClientBlock memory header) {
header.prev_block_hash = data.decodeBytes32();
header.next_block_inner_hash = data.decodeBytes32();
header.inner_lite = data.decodeBlockHeaderInnerLite();
header.inner_rest_hash = data.decodeBytes32();
header.next_bps = data.decodeOptionalValidatorStakes();
header.approvals_after_next = new OptionalSignature[](data.decodeU32());
for (uint i = 0; i < header.approvals_after_next.length; i++) {
header.approvals_after_next[i] = data.decodeOptionalSignature();
}
header.hash = sha256(
abi.encodePacked(
sha256(abi.encodePacked(header.inner_lite.hash, header.inner_rest_hash)),
header.prev_block_hash
)
);
header.next_hash = sha256(abi.encodePacked(header.next_block_inner_hash, header.hash));
}
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 header)
{
header.hash = data.peekSha256(208);
header.height = data.decodeU64();
header.epoch_id = data.decodeBytes32();
header.next_epoch_id = data.decodeBytes32();
header.prev_state_root = data.decodeBytes32();
header.outcome_root = data.decodeBytes32();
header.timestamp = data.decodeU64();
header.next_bp_hash = data.decodeBytes32();
header.block_merkle_root = data.decodeBytes32();
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.6;
interface INearProver {
function proveOutcome(bytes calldata proofData, uint64 blockHeight) external view returns (bool);
}
File 2 of 3: NearProver
// File: @openzeppelin/contracts/math/SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// File: contracts/bridge/AdminControlled.sol
pragma solidity ^0.6;
contract AdminControlled {
address public admin;
uint public paused;
constructor(address _admin, uint flags) public {
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;
}
}
// File: contracts/bridge/INearBridge.sol
pragma solidity ^0.6;
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);
}
// File: contracts/bridge/Borsh.sol
pragma solidity ^0.6;
library Borsh {
using SafeMath for uint256;
struct Data {
uint256 offset;
bytes raw;
}
function from(bytes memory data) internal pure returns (Data memory) {
return Data({offset: 0, raw: data});
}
modifier shift(Data memory data, uint256 size) {
require(data.raw.length >= data.offset + size, "Borsh: Out of range");
_;
data.offset += size;
}
function finished(Data memory data) internal pure returns (bool) {
return data.offset == data.raw.length;
}
function peekKeccak256(Data memory data, uint256 length) internal pure returns (bytes32 res) {
return bytesKeccak256(data.raw, data.offset, length);
}
function bytesKeccak256(
bytes memory ptr,
uint256 offset,
uint256 length
) internal pure returns (bytes32 res) {
// solium-disable-next-line security/no-inline-assembly
assembly {
res := keccak256(add(add(ptr, 32), offset), length)
}
}
function peekSha256(Data memory data, uint256 length) internal view returns (bytes32) {
return bytesSha256(data.raw, data.offset, length);
}
function bytesSha256(
bytes memory ptr,
uint256 offset,
uint256 length
) internal view returns (bytes32) {
bytes32[1] memory result;
// solium-disable-next-line security/no-inline-assembly
assembly {
pop(staticcall(gas(), 0x02, add(add(ptr, 32), offset), length, result, 32))
}
return result[0];
}
function decodeU8(Data memory data) internal pure shift(data, 1) returns (uint8 value) {
value = uint8(data.raw[data.offset]);
}
function decodeI8(Data memory data) internal pure shift(data, 1) returns (int8 value) {
value = int8(data.raw[data.offset]);
}
function decodeU16(Data memory data) internal pure returns (uint16 value) {
value = uint16(decodeU8(data));
value |= (uint16(decodeU8(data)) << 8);
}
function decodeI16(Data memory data) internal pure returns (int16 value) {
value = int16(decodeI8(data));
value |= (int16(decodeI8(data)) << 8);
}
function decodeU32(Data memory data) internal pure returns (uint32 value) {
value = uint32(decodeU16(data));
value |= (uint32(decodeU16(data)) << 16);
}
function decodeI32(Data memory data) internal pure returns (int32 value) {
value = int32(decodeI16(data));
value |= (int32(decodeI16(data)) << 16);
}
function decodeU64(Data memory data) internal pure returns (uint64 value) {
value = uint64(decodeU32(data));
value |= (uint64(decodeU32(data)) << 32);
}
function decodeI64(Data memory data) internal pure returns (int64 value) {
value = int64(decodeI32(data));
value |= (int64(decodeI32(data)) << 32);
}
function decodeU128(Data memory data) internal pure returns (uint128 value) {
value = uint128(decodeU64(data));
value |= (uint128(decodeU64(data)) << 64);
}
function decodeI128(Data memory data) internal pure returns (int128 value) {
value = int128(decodeI64(data));
value |= (int128(decodeI64(data)) << 64);
}
function decodeU256(Data memory data) internal pure returns (uint256 value) {
value = uint256(decodeU128(data));
value |= (uint256(decodeU128(data)) << 128);
}
function decodeI256(Data memory data) internal pure returns (int256 value) {
value = int256(decodeI128(data));
value |= (int256(decodeI128(data)) << 128);
}
function decodeBool(Data memory data) internal pure returns (bool value) {
value = (decodeU8(data) != 0);
}
function decodeBytes(Data memory data) internal pure returns (bytes memory value) {
value = new bytes(decodeU32(data));
for (uint i = 0; i < value.length; i++) {
value[i] = byte(decodeU8(data));
}
}
function decodeBytes32(Data memory data) internal pure shift(data, 32) returns (bytes32 value) {
bytes memory raw = data.raw;
uint256 offset = data.offset;
// solium-disable-next-line security/no-inline-assembly
assembly {
value := mload(add(add(raw, 32), offset))
}
}
function decodeBytes20(Data memory data) internal pure returns (bytes20 value) {
for (uint i = 0; i < 20; i++) {
value |= bytes20(byte(decodeU8(data)) & 0xFF) >> (i * 8);
}
}
// Public key
struct SECP256K1PublicKey {
uint256 x;
uint256 y;
}
function decodeSECP256K1PublicKey(Borsh.Data memory data) internal pure returns (SECP256K1PublicKey memory key) {
key.x = decodeU256(data);
key.y = decodeU256(data);
}
struct ED25519PublicKey {
bytes32 xy;
}
function decodeED25519PublicKey(Borsh.Data memory data) internal pure returns (ED25519PublicKey memory key) {
key.xy = decodeBytes32(data);
}
// Signature
struct SECP256K1Signature {
bytes32 r;
bytes32 s;
uint8 v;
}
function decodeSECP256K1Signature(Borsh.Data memory data) internal pure returns (SECP256K1Signature memory sig) {
sig.r = decodeBytes32(data);
sig.s = decodeBytes32(data);
sig.v = decodeU8(data);
}
struct ED25519Signature {
bytes32[2] rs;
}
function decodeED25519Signature(Borsh.Data memory data) internal pure returns (ED25519Signature memory sig) {
sig.rs[0] = decodeBytes32(data);
sig.rs[1] = decodeBytes32(data);
}
}
// File: contracts/bridge/NearDecoder.sol
pragma solidity ^0.6;
library NearDecoder {
using Borsh for Borsh.Data;
using NearDecoder for Borsh.Data;
struct PublicKey {
uint8 enumIndex;
Borsh.ED25519PublicKey ed25519;
Borsh.SECP256K1PublicKey secp256k1;
}
function decodePublicKey(Borsh.Data memory data) internal pure returns (PublicKey memory key) {
key.enumIndex = data.decodeU8();
if (key.enumIndex == 0) {
key.ed25519 = data.decodeED25519PublicKey();
} else if (key.enumIndex == 1) {
key.secp256k1 = data.decodeSECP256K1PublicKey();
} else {
revert("NearBridge: Only ED25519 and SECP256K1 public keys are supported");
}
}
struct ValidatorStake {
string account_id;
PublicKey public_key;
uint128 stake;
}
function decodeValidatorStake(Borsh.Data memory data) internal pure returns (ValidatorStake memory validatorStake) {
validatorStake.account_id = string(data.decodeBytes());
validatorStake.public_key = data.decodePublicKey();
validatorStake.stake = data.decodeU128();
}
struct OptionalValidatorStakes {
bool none;
ValidatorStake[] validatorStakes;
bytes32 hash; // Additional computable element
}
function decodeOptionalValidatorStakes(Borsh.Data memory data)
internal
view
returns (OptionalValidatorStakes memory stakes)
{
stakes.none = (data.decodeU8() == 0);
if (!stakes.none) {
uint256 start = data.offset;
stakes.validatorStakes = new ValidatorStake[](data.decodeU32());
for (uint i = 0; i < stakes.validatorStakes.length; i++) {
stakes.validatorStakes[i] = data.decodeValidatorStake();
}
uint256 stop = data.offset;
data.offset = start;
stakes.hash = data.peekSha256(stop - start);
data.offset = stop;
}
}
struct Signature {
uint8 enumIndex;
Borsh.ED25519Signature ed25519;
Borsh.SECP256K1Signature secp256k1;
}
function decodeSignature(Borsh.Data memory data) internal pure returns (Signature memory sig) {
sig.enumIndex = data.decodeU8();
if (sig.enumIndex == 0) {
sig.ed25519 = data.decodeED25519Signature();
} else if (sig.enumIndex == 1) {
sig.secp256k1 = data.decodeSECP256K1Signature();
} else {
revert("NearBridge: Only ED25519 and SECP256K1 signatures are supported");
}
}
struct OptionalSignature {
bool none;
Signature signature;
}
function decodeOptionalSignature(Borsh.Data memory data) internal pure returns (OptionalSignature memory sig) {
sig.none = (data.decodeU8() == 0);
if (!sig.none) {
sig.signature = data.decodeSignature();
}
}
struct LightClientBlock {
bytes32 prev_block_hash;
bytes32 next_block_inner_hash;
BlockHeaderInnerLite inner_lite;
bytes32 inner_rest_hash;
OptionalValidatorStakes next_bps;
OptionalSignature[] approvals_after_next;
bytes32 hash;
bytes32 next_hash;
}
struct InitialValidators {
ValidatorStake[] validator_stakes;
}
function decodeInitialValidators(Borsh.Data memory data)
internal
view
returns (InitialValidators memory validators)
{
validators.validator_stakes = new ValidatorStake[](data.decodeU32());
for (uint i = 0; i < validators.validator_stakes.length; i++) {
validators.validator_stakes[i] = data.decodeValidatorStake();
}
}
function decodeLightClientBlock(Borsh.Data memory data) internal view returns (LightClientBlock memory header) {
header.prev_block_hash = data.decodeBytes32();
header.next_block_inner_hash = data.decodeBytes32();
header.inner_lite = data.decodeBlockHeaderInnerLite();
header.inner_rest_hash = data.decodeBytes32();
header.next_bps = data.decodeOptionalValidatorStakes();
header.approvals_after_next = new OptionalSignature[](data.decodeU32());
for (uint i = 0; i < header.approvals_after_next.length; i++) {
header.approvals_after_next[i] = data.decodeOptionalSignature();
}
header.hash = sha256(
abi.encodePacked(
sha256(abi.encodePacked(header.inner_lite.hash, header.inner_rest_hash)),
header.prev_block_hash
)
);
header.next_hash = sha256(abi.encodePacked(header.next_block_inner_hash, header.hash));
}
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 header)
{
header.hash = data.peekSha256(208);
header.height = data.decodeU64();
header.epoch_id = data.decodeBytes32();
header.next_epoch_id = data.decodeBytes32();
header.prev_state_root = data.decodeBytes32();
header.outcome_root = data.decodeBytes32();
header.timestamp = data.decodeU64();
header.next_bp_hash = data.decodeBytes32();
header.block_merkle_root = data.decodeBytes32();
}
}
// File: contracts/ProofDecoder.sol
pragma solidity ^0.6;
library ProofDecoder {
using Borsh for Borsh.Data;
using ProofDecoder for Borsh.Data;
using NearDecoder for Borsh.Data;
struct FullOutcomeProof {
ExecutionOutcomeWithIdAndProof outcome_proof;
MerklePath outcome_root_proof; // TODO: now empty array
BlockHeaderLight block_header_lite;
MerklePath block_proof;
}
function decodeFullOutcomeProof(Borsh.Data memory data) internal view returns (FullOutcomeProof memory proof) {
proof.outcome_proof = data.decodeExecutionOutcomeWithIdAndProof();
proof.outcome_root_proof = data.decodeMerklePath();
proof.block_header_lite = data.decodeBlockHeaderLight();
proof.block_proof = data.decodeMerklePath();
}
struct BlockHeaderLight {
bytes32 prev_block_hash;
bytes32 inner_rest_hash;
NearDecoder.BlockHeaderInnerLite inner_lite;
bytes32 hash; // Computable
}
function decodeBlockHeaderLight(Borsh.Data memory data) internal view returns (BlockHeaderLight memory header) {
header.prev_block_hash = data.decodeBytes32();
header.inner_rest_hash = data.decodeBytes32();
header.inner_lite = data.decodeBlockHeaderInnerLite();
header.hash = sha256(
abi.encodePacked(
sha256(abi.encodePacked(header.inner_lite.hash, header.inner_rest_hash)),
header.prev_block_hash
)
);
}
struct ExecutionStatus {
uint8 enumIndex;
bool unknown;
bool failed;
bytes successValue; /// The final action succeeded and returned some value or an empty vec.
bytes32 successReceiptId; /// The final action of the receipt returned a promise or the signed
/// transaction was converted to a receipt. Contains the receipt_id of the generated receipt.
}
function decodeExecutionStatus(Borsh.Data memory data)
internal
pure
returns (ExecutionStatus memory executionStatus)
{
executionStatus.enumIndex = data.decodeU8();
if (executionStatus.enumIndex == 0) {
executionStatus.unknown = true;
} else if (executionStatus.enumIndex == 1) {
//revert("NearDecoder: decodeExecutionStatus failure case not implemented yet");
// Can avoid revert since ExecutionStatus is latest field in all parent structures
executionStatus.failed = true;
} else if (executionStatus.enumIndex == 2) {
executionStatus.successValue = data.decodeBytes();
} else if (executionStatus.enumIndex == 3) {
executionStatus.successReceiptId = data.decodeBytes32();
} else {
revert("NearDecoder: decodeExecutionStatus index out of range");
}
}
struct ExecutionOutcome {
bytes[] logs; /// Logs from this transaction or receipt.
bytes32[] receipt_ids; /// Receipt IDs generated by this transaction or receipt.
uint64 gas_burnt; /// The amount of the gas burnt by the given transaction or receipt.
uint128 tokens_burnt; /// The total number of the tokens burnt by the given transaction or receipt.
bytes executor_id; /// Hash of the transaction or receipt id that produced this outcome.
ExecutionStatus status; /// Execution status. Contains the result in case of successful execution.
bytes32[] merkelization_hashes;
}
function decodeExecutionOutcome(Borsh.Data memory data) internal view returns (ExecutionOutcome memory outcome) {
outcome.logs = new bytes[](data.decodeU32());
for (uint i = 0; i < outcome.logs.length; i++) {
outcome.logs[i] = data.decodeBytes();
}
uint256 start = data.offset;
outcome.receipt_ids = new bytes32[](data.decodeU32());
for (uint i = 0; i < outcome.receipt_ids.length; i++) {
outcome.receipt_ids[i] = data.decodeBytes32();
}
outcome.gas_burnt = data.decodeU64();
outcome.tokens_burnt = data.decodeU128();
outcome.executor_id = data.decodeBytes();
outcome.status = data.decodeExecutionStatus();
uint256 stop = data.offset;
outcome.merkelization_hashes = new bytes32[](1 + outcome.logs.length);
data.offset = start;
outcome.merkelization_hashes[0] = data.peekSha256(stop - start);
data.offset = stop;
for (uint i = 0; i < outcome.logs.length; i++) {
outcome.merkelization_hashes[i + 1] = sha256(outcome.logs[i]);
}
}
struct ExecutionOutcomeWithId {
bytes32 id; /// The transaction hash or the receipt ID.
ExecutionOutcome outcome;
bytes32 hash;
}
function decodeExecutionOutcomeWithId(Borsh.Data memory data)
internal
view
returns (ExecutionOutcomeWithId memory outcome)
{
outcome.id = data.decodeBytes32();
outcome.outcome = data.decodeExecutionOutcome();
uint256 len = 1 + outcome.outcome.merkelization_hashes.length;
outcome.hash = sha256(
abi.encodePacked(
uint8((len >> 0) & 0xFF),
uint8((len >> 8) & 0xFF),
uint8((len >> 16) & 0xFF),
uint8((len >> 24) & 0xFF),
outcome.id,
outcome.outcome.merkelization_hashes
)
);
}
struct MerklePathItem {
bytes32 hash;
uint8 direction; // 0 = left, 1 = right
}
function decodeMerklePathItem(Borsh.Data memory data) internal pure returns (MerklePathItem memory item) {
item.hash = data.decodeBytes32();
item.direction = data.decodeU8();
require(item.direction < 2, "ProofDecoder: MerklePathItem direction should be 0 or 1");
}
struct MerklePath {
MerklePathItem[] items;
}
function decodeMerklePath(Borsh.Data memory data) internal pure returns (MerklePath memory path) {
path.items = new MerklePathItem[](data.decodeU32());
for (uint i = 0; i < path.items.length; i++) {
path.items[i] = data.decodeMerklePathItem();
}
}
struct ExecutionOutcomeWithIdAndProof {
MerklePath proof;
bytes32 block_hash;
ExecutionOutcomeWithId outcome_with_id;
}
function decodeExecutionOutcomeWithIdAndProof(Borsh.Data memory data)
internal
view
returns (ExecutionOutcomeWithIdAndProof memory outcome)
{
outcome.proof = data.decodeMerklePath();
outcome.block_hash = data.decodeBytes32();
outcome.outcome_with_id = data.decodeExecutionOutcomeWithId();
}
}
// File: contracts/INearProver.sol
pragma solidity ^0.6;
interface INearProver {
function proveOutcome(bytes calldata proofData, uint64 blockHeight) external view returns (bool);
}
// File: contracts/NearProver.sol
pragma solidity ^0.6;
contract NearProver is INearProver, AdminControlled {
using SafeMath for uint256;
using Borsh for Borsh.Data;
using NearDecoder for Borsh.Data;
using ProofDecoder for Borsh.Data;
INearBridge public bridge;
constructor(
INearBridge _bridge,
address _admin,
uint _pausedFlags
) public AdminControlled(_admin, _pausedFlags) {
bridge = _bridge;
}
uint constant UNPAUSE_ALL = 0;
uint constant PAUSED_VERIFY = 1;
function proveOutcome(bytes memory proofData, uint64 blockHeight)
public
view
override
pausable(PAUSED_VERIFY)
returns (bool)
{
Borsh.Data memory borshData = Borsh.from(proofData);
ProofDecoder.FullOutcomeProof memory fullOutcomeProof = borshData.decodeFullOutcomeProof();
require(borshData.finished(), "NearProver: argument should be exact borsh serialization");
bytes32 hash =
_computeRoot(fullOutcomeProof.outcome_proof.outcome_with_id.hash, fullOutcomeProof.outcome_proof.proof);
hash = sha256(abi.encodePacked(hash));
hash = _computeRoot(hash, fullOutcomeProof.outcome_root_proof);
require(
hash == fullOutcomeProof.block_header_lite.inner_lite.outcome_root,
"NearProver: outcome merkle proof is not valid"
);
bytes32 expectedBlockMerkleRoot = bridge.blockMerkleRoots(blockHeight);
require(
_computeRoot(fullOutcomeProof.block_header_lite.hash, fullOutcomeProof.block_proof) ==
expectedBlockMerkleRoot,
"NearProver: block proof is not valid"
);
return true;
}
function _computeRoot(bytes32 node, ProofDecoder.MerklePath memory proof) internal pure returns (bytes32 hash) {
hash = node;
for (uint i = 0; i < proof.items.length; i++) {
ProofDecoder.MerklePathItem memory item = proof.items[i];
if (item.direction == 0) {
hash = sha256(abi.encodePacked(item.hash, hash));
} else {
hash = sha256(abi.encodePacked(hash, item.hash));
}
}
}
}File 3 of 3: NearBridge
{"AdminControlled.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\ncontract AdminControlled {\n address public admin;\n uint public paused;\n\n constructor(address _admin, uint flags) {\n admin = _admin;\n paused = flags;\n }\n\n modifier onlyAdmin {\n require(msg.sender == admin);\n _;\n }\n\n modifier pausable(uint flag) {\n require((paused \u0026 flag) == 0 || msg.sender == admin);\n _;\n }\n\n function adminPause(uint flags) public onlyAdmin {\n paused = flags;\n }\n\n function adminSstore(uint key, uint value) public onlyAdmin {\n assembly {\n sstore(key, value)\n }\n }\n\n function adminSstoreWithMask(\n uint key,\n uint value,\n uint mask\n ) public onlyAdmin {\n assembly {\n let oldval := sload(key)\n sstore(key, xor(and(xor(value, oldval), mask), oldval))\n }\n }\n\n function adminSendEth(address payable destination, uint amount) public onlyAdmin {\n destination.transfer(amount);\n }\n\n function adminReceiveEth() public payable onlyAdmin {}\n\n function adminDelegatecall(address target, bytes memory data) public payable onlyAdmin returns (bytes memory) {\n (bool success, bytes memory rdata) = target.delegatecall(data);\n require(success);\n return rdata;\n }\n}\n"},"Borsh.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\nimport \"./Utils.sol\";\n\nlibrary Borsh {\n using Borsh for Data;\n\n struct Data {\n uint ptr;\n uint end;\n }\n\n function from(bytes memory data) internal pure returns (Data memory res) {\n uint ptr;\n assembly {\n ptr := data\n }\n unchecked {\n res.ptr = ptr + 32;\n res.end = res.ptr + Utils.readMemory(ptr);\n }\n }\n\n // 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.\n function requireSpace(Data memory data, uint length) internal pure {\n unchecked {\n require(data.ptr + length \u003c= data.end, \"Parse error: unexpected EOI\");\n }\n }\n\n function read(Data memory data, uint length) internal pure returns (bytes32 res) {\n data.requireSpace(length);\n res = bytes32(Utils.readMemory(data.ptr));\n unchecked {\n data.ptr += length;\n }\n return res;\n }\n\n function done(Data memory data) internal pure {\n require(data.ptr == data.end, \"Parse error: EOI expected\");\n }\n\n // Same considerations as for requireSpace.\n function peekKeccak256(Data memory data, uint length) internal pure returns (bytes32) {\n data.requireSpace(length);\n return Utils.keccak256Raw(data.ptr, length);\n }\n\n // Same considerations as for requireSpace.\n function peekSha256(Data memory data, uint length) internal view returns (bytes32) {\n data.requireSpace(length);\n return Utils.sha256Raw(data.ptr, length);\n }\n\n function decodeU8(Data memory data) internal pure returns (uint8) {\n return uint8(bytes1(data.read(1)));\n }\n\n function decodeU16(Data memory data) internal pure returns (uint16) {\n return Utils.swapBytes2(uint16(bytes2(data.read(2))));\n }\n\n function decodeU32(Data memory data) internal pure returns (uint32) {\n return Utils.swapBytes4(uint32(bytes4(data.read(4))));\n }\n\n function decodeU64(Data memory data) internal pure returns (uint64) {\n return Utils.swapBytes8(uint64(bytes8(data.read(8))));\n }\n\n function decodeU128(Data memory data) internal pure returns (uint128) {\n return Utils.swapBytes16(uint128(bytes16(data.read(16))));\n }\n\n function decodeU256(Data memory data) internal pure returns (uint256) {\n return Utils.swapBytes32(uint256(data.read(32)));\n }\n\n function decodeBytes20(Data memory data) internal pure returns (bytes20) {\n return bytes20(data.read(20));\n }\n\n function decodeBytes32(Data memory data) internal pure returns (bytes32) {\n return data.read(32);\n }\n\n function decodeBool(Data memory data) internal pure returns (bool) {\n uint8 res = data.decodeU8();\n require(res \u003c= 1, \"Parse error: invalid bool\");\n return res != 0;\n }\n\n function skipBytes(Data memory data) internal pure {\n uint length = data.decodeU32();\n data.requireSpace(length);\n unchecked {\n data.ptr += length;\n }\n }\n\n function decodeBytes(Data memory data) internal pure returns (bytes memory res) {\n uint length = data.decodeU32();\n data.requireSpace(length);\n res = Utils.memoryToBytes(data.ptr, length);\n unchecked {\n data.ptr += length;\n }\n }\n}\n"},"Ed25519.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\ncontract Ed25519 {\n // Computes (v^(2^250-1), v^11) mod p\n function pow22501(uint256 v) private pure returns (uint256 p22501, uint256 p11) {\n p11 = mulmod(v, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n p22501 = mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n p22501 = mulmod(\n mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n v,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n p11 = mulmod(p22501, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n p22501 = mulmod(\n mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n p22501,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n uint256 b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n }\n\n function check(\n bytes32 k,\n bytes32 r,\n bytes32 s,\n bytes32 m1,\n bytes9 m2\n ) public pure returns (bool) {\n unchecked {\n uint256 hh;\n // Step 1: compute SHA-512(R, A, M)\n {\n uint256[5][16] memory kk = [\n [\n uint256(0x428a2f98_d728ae22),\n uint256(0xe49b69c1_9ef14ad2),\n uint256(0x27b70a85_46d22ffc),\n uint256(0x19a4c116_b8d2d0c8),\n uint256(0xca273ece_ea26619c)\n ],\n [\n uint256(0x71374491_23ef65cd),\n uint256(0xefbe4786_384f25e3),\n uint256(0x2e1b2138_5c26c926),\n uint256(0x1e376c08_5141ab53),\n uint256(0xd186b8c7_21c0c207)\n ],\n [\n uint256(0xb5c0fbcf_ec4d3b2f),\n uint256(0xfc19dc6_8b8cd5b5),\n uint256(0x4d2c6dfc_5ac42aed),\n uint256(0x2748774c_df8eeb99),\n uint256(0xeada7dd6_cde0eb1e)\n ],\n [\n uint256(0xe9b5dba5_8189dbbc),\n uint256(0x240ca1cc_77ac9c65),\n uint256(0x53380d13_9d95b3df),\n uint256(0x34b0bcb5_e19b48a8),\n uint256(0xf57d4f7f_ee6ed178)\n ],\n [\n uint256(0x3956c25b_f348b538),\n uint256(0x2de92c6f_592b0275),\n uint256(0x650a7354_8baf63de),\n uint256(0x391c0cb3_c5c95a63),\n uint256(0x6f067aa_72176fba)\n ],\n [\n uint256(0x59f111f1_b605d019),\n uint256(0x4a7484aa_6ea6e483),\n uint256(0x766a0abb_3c77b2a8),\n uint256(0x4ed8aa4a_e3418acb),\n uint256(0xa637dc5_a2c898a6)\n ],\n [\n uint256(0x923f82a4_af194f9b),\n uint256(0x5cb0a9dc_bd41fbd4),\n uint256(0x81c2c92e_47edaee6),\n uint256(0x5b9cca4f_7763e373),\n uint256(0x113f9804_bef90dae)\n ],\n [\n uint256(0xab1c5ed5_da6d8118),\n uint256(0x76f988da_831153b5),\n uint256(0x92722c85_1482353b),\n uint256(0x682e6ff3_d6b2b8a3),\n uint256(0x1b710b35_131c471b)\n ],\n [\n uint256(0xd807aa98_a3030242),\n uint256(0x983e5152_ee66dfab),\n uint256(0xa2bfe8a1_4cf10364),\n uint256(0x748f82ee_5defb2fc),\n uint256(0x28db77f5_23047d84)\n ],\n [\n uint256(0x12835b01_45706fbe),\n uint256(0xa831c66d_2db43210),\n uint256(0xa81a664b_bc423001),\n uint256(0x78a5636f_43172f60),\n uint256(0x32caab7b_40c72493)\n ],\n [\n uint256(0x243185be_4ee4b28c),\n uint256(0xb00327c8_98fb213f),\n uint256(0xc24b8b70_d0f89791),\n uint256(0x84c87814_a1f0ab72),\n uint256(0x3c9ebe0a_15c9bebc)\n ],\n [\n uint256(0x550c7dc3_d5ffb4e2),\n uint256(0xbf597fc7_beef0ee4),\n uint256(0xc76c51a3_0654be30),\n uint256(0x8cc70208_1a6439ec),\n uint256(0x431d67c4_9c100d4c)\n ],\n [\n uint256(0x72be5d74_f27b896f),\n uint256(0xc6e00bf3_3da88fc2),\n uint256(0xd192e819_d6ef5218),\n uint256(0x90befffa_23631e28),\n uint256(0x4cc5d4be_cb3e42b6)\n ],\n [\n uint256(0x80deb1fe_3b1696b1),\n uint256(0xd5a79147_930aa725),\n uint256(0xd6990624_5565a910),\n uint256(0xa4506ceb_de82bde9),\n uint256(0x597f299c_fc657e2a)\n ],\n [\n uint256(0x9bdc06a7_25c71235),\n uint256(0x6ca6351_e003826f),\n uint256(0xf40e3585_5771202a),\n uint256(0xbef9a3f7_b2c67915),\n uint256(0x5fcb6fab_3ad6faec)\n ],\n [\n uint256(0xc19bf174_cf692694),\n uint256(0x14292967_0a0e6e70),\n uint256(0x106aa070_32bbd1b8),\n uint256(0xc67178f2_e372532b),\n uint256(0x6c44198c_4a475817)\n ]\n ];\n uint256 w0 = (uint256(r) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_ffffffff_ffffffff) |\n ((uint256(r) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64) |\n ((uint256(r) \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64);\n uint256 w1 = (uint256(k) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_ffffffff_ffffffff) |\n ((uint256(k) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64) |\n ((uint256(k) \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64);\n uint256 w2 = (uint256(m1) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_ffffffff_ffffffff) |\n ((uint256(m1) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64) |\n ((uint256(m1) \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64);\n uint256 w3 = (uint256(bytes32(m2)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_00000000_00000000) |\n ((uint256(bytes32(m2)) \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64) |\n 0x800000_00000000_00000000_00000348;\n uint256 a = 0x6a09e667_f3bcc908;\n uint256 b = 0xbb67ae85_84caa73b;\n uint256 c = 0x3c6ef372_fe94f82b;\n uint256 d = 0xa54ff53a_5f1d36f1;\n uint256 e = 0x510e527f_ade682d1;\n uint256 f = 0x9b05688c_2b3e6c1f;\n uint256 g = 0x1f83d9ab_fb41bd6b;\n uint256 h = 0x5be0cd19_137e2179;\n for (uint256 i = 0; ; i++) {\n // Round 16 * i\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[0][i];\n temp1 += w0 \u003e\u003e 192;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 1\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[1][i];\n temp1 += w0 \u003e\u003e 64;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 2\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[2][i];\n temp1 += w0 \u003e\u003e 128;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 3\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[3][i];\n temp1 += w0;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 4\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[4][i];\n temp1 += w1 \u003e\u003e 192;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 5\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[5][i];\n temp1 += w1 \u003e\u003e 64;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 6\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[6][i];\n temp1 += w1 \u003e\u003e 128;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 7\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[7][i];\n temp1 += w1;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 8\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[8][i];\n temp1 += w2 \u003e\u003e 192;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 9\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[9][i];\n temp1 += w2 \u003e\u003e 64;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 10\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[10][i];\n temp1 += w2 \u003e\u003e 128;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 11\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[11][i];\n temp1 += w2;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 12\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[12][i];\n temp1 += w3 \u003e\u003e 192;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 13\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[13][i];\n temp1 += w3 \u003e\u003e 64;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 14\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[14][i];\n temp1 += w3 \u003e\u003e 128;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n // Round 16 * i + 15\n {\n uint256 temp1;\n uint256 temp2;\n e \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = e | (e \u003c\u003c 64);\n uint256 s1 = (ss \u003e\u003e 14) ^ (ss \u003e\u003e 18) ^ (ss \u003e\u003e 41);\n uint256 ch = (e \u0026 (f ^ g)) ^ g;\n temp1 = h + s1 + ch;\n }\n temp1 += kk[15][i];\n temp1 += w3;\n a \u0026= 0xffffffff_ffffffff;\n {\n uint256 ss = a | (a \u003c\u003c 64);\n uint256 s0 = (ss \u003e\u003e 28) ^ (ss \u003e\u003e 34) ^ (ss \u003e\u003e 39);\n uint256 maj = (a \u0026 (b | c)) | (b \u0026 c);\n temp2 = s0 + maj;\n }\n h = g;\n g = f;\n f = e;\n e = d + temp1;\n d = c;\n c = b;\n b = a;\n a = temp1 + temp2;\n }\n if (i == 4) {\n break;\n }\n // Message expansion\n uint256 t0 = w0;\n uint256 t1 = w1;\n {\n uint256 t2 = w2;\n uint256 t3 = w3;\n {\n uint256 n1 = t0 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n n1 +=\n ((t2 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 128) |\n ((t2 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64);\n {\n uint256 u1 = ((t0 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64) |\n ((t0 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 128);\n uint256 uu1 = u1 | (u1 \u003c\u003c 64);\n n1 +=\n ((uu1 \u003c\u003c 63) ^ (uu1 \u003c\u003c 56) ^ (u1 \u003c\u003c 57)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n {\n uint256 v1 = t3 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n uint256 vv1 = v1 | (v1 \u003c\u003c 64);\n n1 +=\n ((vv1 \u003c\u003c 45) ^ (vv1 \u003c\u003c 3) ^ (v1 \u003c\u003c 58)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n n1 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n uint256 n2 = t0 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n n2 += ((t2 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t3 \u003e\u003e 192);\n {\n uint256 u2 = ((t0 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t1 \u003e\u003e 192);\n uint256 uu2 = u2 | (u2 \u003c\u003c 64);\n n2 +=\n ((uu2 \u003e\u003e 1) ^ (uu2 \u003e\u003e 8) ^ (u2 \u003e\u003e 7)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n {\n uint256 vv2 = n1 | (n1 \u003e\u003e 64);\n n2 +=\n ((vv2 \u003e\u003e 19) ^ (vv2 \u003e\u003e 61) ^ (n1 \u003e\u003e 70)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n n2 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n t0 = n1 | n2;\n }\n {\n uint256 n1 = t1 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n n1 +=\n ((t3 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 128) |\n ((t3 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64);\n {\n uint256 u1 = ((t1 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64) |\n ((t1 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 128);\n uint256 uu1 = u1 | (u1 \u003c\u003c 64);\n n1 +=\n ((uu1 \u003c\u003c 63) ^ (uu1 \u003c\u003c 56) ^ (u1 \u003c\u003c 57)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n {\n uint256 v1 = t0 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n uint256 vv1 = v1 | (v1 \u003c\u003c 64);\n n1 +=\n ((vv1 \u003c\u003c 45) ^ (vv1 \u003c\u003c 3) ^ (v1 \u003c\u003c 58)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n n1 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n uint256 n2 = t1 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n n2 += ((t3 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t0 \u003e\u003e 192);\n {\n uint256 u2 = ((t1 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t2 \u003e\u003e 192);\n uint256 uu2 = u2 | (u2 \u003c\u003c 64);\n n2 +=\n ((uu2 \u003e\u003e 1) ^ (uu2 \u003e\u003e 8) ^ (u2 \u003e\u003e 7)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n {\n uint256 vv2 = n1 | (n1 \u003e\u003e 64);\n n2 +=\n ((vv2 \u003e\u003e 19) ^ (vv2 \u003e\u003e 61) ^ (n1 \u003e\u003e 70)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n n2 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n t1 = n1 | n2;\n }\n {\n uint256 n1 = t2 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n n1 +=\n ((t0 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 128) |\n ((t0 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64);\n {\n uint256 u1 = ((t2 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64) |\n ((t2 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 128);\n uint256 uu1 = u1 | (u1 \u003c\u003c 64);\n n1 +=\n ((uu1 \u003c\u003c 63) ^ (uu1 \u003c\u003c 56) ^ (u1 \u003c\u003c 57)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n {\n uint256 v1 = t1 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n uint256 vv1 = v1 | (v1 \u003c\u003c 64);\n n1 +=\n ((vv1 \u003c\u003c 45) ^ (vv1 \u003c\u003c 3) ^ (v1 \u003c\u003c 58)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n n1 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n uint256 n2 = t2 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n n2 += ((t0 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t1 \u003e\u003e 192);\n {\n uint256 u2 = ((t2 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t3 \u003e\u003e 192);\n uint256 uu2 = u2 | (u2 \u003c\u003c 64);\n n2 +=\n ((uu2 \u003e\u003e 1) ^ (uu2 \u003e\u003e 8) ^ (u2 \u003e\u003e 7)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n {\n uint256 vv2 = n1 | (n1 \u003e\u003e 64);\n n2 +=\n ((vv2 \u003e\u003e 19) ^ (vv2 \u003e\u003e 61) ^ (n1 \u003e\u003e 70)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n n2 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n t2 = n1 | n2;\n }\n {\n uint256 n1 = t3 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n n1 +=\n ((t1 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 128) |\n ((t1 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 64);\n {\n uint256 u1 = ((t3 \u0026 0xffffffff_ffffffff_00000000_00000000) \u003c\u003c 64) |\n ((t3 \u0026 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) \u003e\u003e 128);\n uint256 uu1 = u1 | (u1 \u003c\u003c 64);\n n1 +=\n ((uu1 \u003c\u003c 63) ^ (uu1 \u003c\u003c 56) ^ (u1 \u003c\u003c 57)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n {\n uint256 v1 = t2 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n uint256 vv1 = v1 | (v1 \u003c\u003c 64);\n n1 +=\n ((vv1 \u003c\u003c 45) ^ (vv1 \u003c\u003c 3) ^ (v1 \u003c\u003c 58)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n }\n n1 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000;\n uint256 n2 = t3 \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n n2 += ((t1 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t2 \u003e\u003e 192);\n {\n uint256 u2 = ((t3 \u0026 0xffffffff_ffffffff) \u003c\u003c 128) | (t0 \u003e\u003e 192);\n uint256 uu2 = u2 | (u2 \u003c\u003c 64);\n n2 +=\n ((uu2 \u003e\u003e 1) ^ (uu2 \u003e\u003e 8) ^ (u2 \u003e\u003e 7)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n {\n uint256 vv2 = n1 | (n1 \u003e\u003e 64);\n n2 +=\n ((vv2 \u003e\u003e 19) ^ (vv2 \u003e\u003e 61) ^ (n1 \u003e\u003e 70)) \u0026\n 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n }\n n2 \u0026= 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff;\n t3 = n1 | n2;\n }\n w3 = t3;\n w2 = t2;\n }\n w1 = t1;\n w0 = t0;\n }\n uint256 h0 = ((a + 0x6a09e667_f3bcc908) \u0026 0xffffffff_ffffffff) |\n (((b + 0xbb67ae85_84caa73b) \u0026 0xffffffff_ffffffff) \u003c\u003c 64) |\n (((c + 0x3c6ef372_fe94f82b) \u0026 0xffffffff_ffffffff) \u003c\u003c 128) |\n ((d + 0xa54ff53a_5f1d36f1) \u003c\u003c 192);\n h0 =\n ((h0 \u0026 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) \u003c\u003c 8) |\n ((h0 \u0026 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) \u003e\u003e 8);\n h0 =\n ((h0 \u0026 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) \u003c\u003c 16) |\n ((h0 \u0026 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) \u003e\u003e 16);\n h0 =\n ((h0 \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) \u003c\u003c 32) |\n ((h0 \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) \u003e\u003e 32);\n uint256 h1 = ((e + 0x510e527f_ade682d1) \u0026 0xffffffff_ffffffff) |\n (((f + 0x9b05688c_2b3e6c1f) \u0026 0xffffffff_ffffffff) \u003c\u003c 64) |\n (((g + 0x1f83d9ab_fb41bd6b) \u0026 0xffffffff_ffffffff) \u003c\u003c 128) |\n ((h + 0x5be0cd19_137e2179) \u003c\u003c 192);\n h1 =\n ((h1 \u0026 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) \u003c\u003c 8) |\n ((h1 \u0026 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) \u003e\u003e 8);\n h1 =\n ((h1 \u0026 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) \u003c\u003c 16) |\n ((h1 \u0026 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) \u003e\u003e 16);\n h1 =\n ((h1 \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) \u003c\u003c 32) |\n ((h1 \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) \u003e\u003e 32);\n hh = addmod(\n h0,\n mulmod(\n h1,\n 0xfffffff_ffffffff_ffffffff_fffffffe_c6ef5bf4_737dcf70_d6ec3174_8d98951d,\n 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed\n ),\n 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed\n );\n }\n // Step 2: unpack k\n k = bytes32(\n ((uint256(k) \u0026 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) \u003c\u003c 8) |\n ((uint256(k) \u0026 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) \u003e\u003e 8)\n );\n k = bytes32(\n ((uint256(k) \u0026 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) \u003c\u003c 16) |\n ((uint256(k) \u0026 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) \u003e\u003e 16)\n );\n k = bytes32(\n ((uint256(k) \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) \u003c\u003c 32) |\n ((uint256(k) \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) \u003e\u003e 32)\n );\n k = bytes32(\n ((uint256(k) \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) \u003c\u003c 64) |\n ((uint256(k) \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) \u003e\u003e 64)\n );\n k = bytes32((uint256(k) \u003c\u003c 128) | (uint256(k) \u003e\u003e 128));\n uint256 ky = uint256(k) \u0026 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff;\n uint256 kx;\n {\n uint256 ky2 = mulmod(ky, ky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n uint256 u = addmod(\n ky2,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffec,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 v = mulmod(\n ky2,\n 0x52036cee_2b6ffe73_8cc74079_7779e898_00700a4d_4141d8ab_75eb4dca_135978a3,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n ) + 1;\n uint256 t = mulmod(u, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n (kx, ) = pow22501(t);\n kx = mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n kx = mulmod(\n u,\n mulmod(\n mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n t,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n ),\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n t = mulmod(\n mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n v,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n if (t != u) {\n if (t != 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - u) {\n return false;\n }\n kx = mulmod(\n kx,\n 0x2b832480_4fc1df0b_2b4d0099_3dfbd7a7_2f431806_ad2fe478_c4ee1b27_4a0ea0b0,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n }\n if ((kx \u0026 1) != uint256(k) \u003e\u003e 255) {\n kx = 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - kx;\n }\n // Verify s\n s = bytes32(\n ((uint256(s) \u0026 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) \u003c\u003c 8) |\n ((uint256(s) \u0026 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) \u003e\u003e 8)\n );\n s = bytes32(\n ((uint256(s) \u0026 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) \u003c\u003c 16) |\n ((uint256(s) \u0026 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) \u003e\u003e 16)\n );\n s = bytes32(\n ((uint256(s) \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) \u003c\u003c 32) |\n ((uint256(s) \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) \u003e\u003e 32)\n );\n s = bytes32(\n ((uint256(s) \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) \u003c\u003c 64) |\n ((uint256(s) \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) \u003e\u003e 64)\n );\n s = bytes32((uint256(s) \u003c\u003c 128) | (uint256(s) \u003e\u003e 128));\n if (uint256(s) \u003e= 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed) {\n return false;\n }\n uint256 vx;\n uint256 vu;\n uint256 vy;\n uint256 vv;\n // Step 3: compute multiples of k\n uint256[8][3][2] memory tables;\n {\n uint256 ks = ky + kx;\n uint256 kd = ky + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - kx;\n uint256 k2dt = mulmod(\n mulmod(kx, ky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n 0x2406d9dc_56dffce7_198e80f2_eef3d130_00e0149a_8283b156_ebd69b94_26b2f159,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 kky = ky;\n uint256 kkx = kx;\n uint256 kku = 1;\n uint256 kkv = 1;\n {\n uint256 xx = mulmod(\n kkx,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy = mulmod(\n kky,\n kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz = mulmod(\n kku,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xx2 = mulmod(\n xx,\n xx,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy2 = mulmod(\n yy,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xxyy = mulmod(\n xx,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz2 = mulmod(\n zz,\n zz,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n kkx = xxyy + xxyy;\n kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n kky = xx2 + yy2;\n kkv = addmod(\n zz2 + zz2,\n 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n {\n uint256 xx = mulmod(\n kkx,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy = mulmod(\n kky,\n kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz = mulmod(\n kku,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xx2 = mulmod(\n xx,\n xx,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy2 = mulmod(\n yy,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xxyy = mulmod(\n xx,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz2 = mulmod(\n zz,\n zz,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n kkx = xxyy + xxyy;\n kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n kky = xx2 + yy2;\n kkv = addmod(\n zz2 + zz2,\n 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n {\n uint256 xx = mulmod(\n kkx,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy = mulmod(\n kky,\n kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz = mulmod(\n kku,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xx2 = mulmod(\n xx,\n xx,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy2 = mulmod(\n yy,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xxyy = mulmod(\n xx,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz2 = mulmod(\n zz,\n zz,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n kkx = xxyy + xxyy;\n kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n kky = xx2 + yy2;\n kkv = addmod(\n zz2 + zz2,\n 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n uint256 cprod = 1;\n uint256[8][3][2] memory tables_ = tables;\n for (uint256 i = 0; ; i++) {\n uint256 cs;\n uint256 cd;\n uint256 ct;\n uint256 c2z;\n {\n uint256 cx = mulmod(\n kkx,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 cy = mulmod(\n kky,\n kku,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 cz = mulmod(\n kku,\n kkv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n ct = mulmod(\n kkx,\n kky,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n cs = cy + cx;\n cd = cy - cx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n c2z = cz + cz;\n }\n tables_[1][0][i] = cs;\n tables_[1][1][i] = cd;\n tables_[1][2][i] = mulmod(\n ct,\n 0x2406d9dc_56dffce7_198e80f2_eef3d130_00e0149a_8283b156_ebd69b94_26b2f159,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n tables_[0][0][i] = c2z;\n tables_[0][1][i] = cprod;\n cprod = mulmod(\n cprod,\n c2z,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n if (i == 7) {\n break;\n }\n uint256 ab = mulmod(\n cs,\n ks,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 aa = mulmod(\n cd,\n kd,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ac = mulmod(\n ct,\n k2dt,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n kkx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n kku = addmod(c2z, ac, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n kky = ab + aa;\n kkv = addmod(\n c2z,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - ac,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n uint256 t;\n (cprod, t) = pow22501(cprod);\n cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n cprod = mulmod(cprod, t, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n for (uint256 i = 7; ; i--) {\n uint256 cinv = mulmod(\n cprod,\n tables_[0][1][i],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n tables_[1][0][i] = mulmod(\n tables_[1][0][i],\n cinv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n tables_[1][1][i] = mulmod(\n tables_[1][1][i],\n cinv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n tables_[1][2][i] = mulmod(\n tables_[1][2][i],\n cinv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n if (i == 0) {\n break;\n }\n cprod = mulmod(\n cprod,\n tables_[0][0][i],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n tables_[0] = [\n [\n 0x43e7ce9d_19ea5d32_9385a44c_321ea161_67c996e3_7dc6070c_97de49e3_7ac61db9,\n 0x40cff344_25d8ec30_a3bb74ba_58cd5854_fa1e3818_6ad0d31e_bc8ae251_ceb2c97e,\n 0x459bd270_46e8dd45_aea7008d_b87a5a8f_79067792_53d64523_58951859_9fdfbf4b,\n 0x69fdd1e2_8c23cc38_94d0c8ff_90e76f6d_5b6e4c2e_620136d0_4dd83c4a_51581ab9,\n 0x54dceb34_13ce5cfa_11196dfc_960b6eda_f4b380c6_d4d23784_19cc0279_ba49c5f3,\n 0x4e24184d_d71a3d77_eef3729f_7f8cf7c1_7224cf40_aa7b9548_b9942f3c_5084ceed,\n 0x5a0e5aab_20262674_ae117576_1cbf5e88_9b52a55f_d7ac5027_c228cebd_c8d2360a,\n 0x26239334_073e9b38_c6285955_6d451c3d_cc8d30e8_4b361174_f488eadd_e2cf17d9\n ],\n [\n 0x227e97c9_4c7c0933_d2e0c21a_3447c504_fe9ccf82_e8a05f59_ce881c82_eba0489f,\n 0x226a3e0e_cc4afec6_fd0d2884_13014a9d_bddecf06_c1a2f0bb_702ba77c_613d8209,\n 0x34d7efc8_51d45c5e_71efeb0f_235b7946_91de6228_877569b3_a8d52bf0_58b8a4a0,\n 0x3c1f5fb3_ca7166fc_e1471c9b_752b6d28_c56301ad_7b65e845_1b2c8c55_26726e12,\n 0x6102416c_f02f02ff_5be75275_f55f28db_89b2a9d2_456b860c_e22fc0e5_031f7cc5,\n 0x40adf677_f1bfdae0_57f0fd17_9c126179_18ddaa28_91a6530f_b1a4294f_a8665490,\n 0x61936f3c_41560904_6187b8ba_a978cbc9_b4789336_3ae5a3cc_7d909f36_35ae7f48,\n 0x562a9662_b6ec47f9_e979d473_c02b51e4_42336823_8c58ddb5_2f0e5c6a_180e6410\n ],\n [\n 0x3788bdb4_4f8632d4_2d0dbee5_eea1acc6_136cf411_e655624f_55e48902_c3bd5534,\n 0x6190cf2c_2a7b5ad7_69d594a8_2844f23b_4167fa7c_8ac30e51_aa6cfbeb_dcd4b945,\n 0x65f77870_96be9204_123a71f3_ac88a87b_e1513217_737d6a1e_2f3a13a4_3d7e3a9a,\n 0x23af32d_bfa67975_536479a7_a7ce74a0_2142147f_ac048018_7f1f1334_9cda1f2d,\n 0x64fc44b7_fc6841bd_db0ced8b_8b0fe675_9137ef87_ee966512_15fc1dbc_d25c64dc,\n 0x1434aa37_48b701d5_b69df3d7_d340c1fe_3f6b9c1e_fc617484_caadb47e_382f4475,\n 0x457a6da8_c962ef35_f2b21742_3e5844e9_d2353452_7e8ea429_0d24e3dd_f21720c6,\n 0x63b9540c_eb60ccb5_1e4d989d_956e053c_f2511837_efb79089_d2ff4028_4202c53d\n ]\n ];\n }\n // Step 4: compute s*G - h*A\n {\n uint256 ss = uint256(s) \u003c\u003c 3;\n uint256 hhh = hh + 0x80000000_00000000_00000000_00000000_a6f7cef5_17bce6b2_c09318d2_e7ae9f60;\n uint256 vvx = 0;\n uint256 vvu = 1;\n uint256 vvy = 1;\n uint256 vvv = 1;\n for (uint256 i = 252; ; i--) {\n uint256 bit = 8 \u003c\u003c i;\n if ((ss \u0026 bit) != 0) {\n uint256 ws;\n uint256 wd;\n uint256 wz;\n uint256 wt;\n {\n uint256 wx = mulmod(\n vvx,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 wy = mulmod(\n vvy,\n vvu,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n ws = wy + wx;\n wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n wz = mulmod(\n vvu,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n wt = mulmod(\n vvx,\n vvy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n uint256 j = (ss \u003e\u003e i) \u0026 7;\n ss \u0026= ~(7 \u003c\u003c i);\n uint256[8][3][2] memory tables_ = tables;\n uint256 aa = mulmod(\n wd,\n tables_[0][1][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ab = mulmod(\n ws,\n tables_[0][0][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ac = mulmod(\n wt,\n tables_[0][2][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n vvu = wz + ac;\n vvy = ab + aa;\n vvv = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n }\n if ((hhh \u0026 bit) != 0) {\n uint256 ws;\n uint256 wd;\n uint256 wz;\n uint256 wt;\n {\n uint256 wx = mulmod(\n vvx,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 wy = mulmod(\n vvy,\n vvu,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n ws = wy + wx;\n wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n wz = mulmod(\n vvu,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n wt = mulmod(\n vvx,\n vvy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n uint256 j = (hhh \u003e\u003e i) \u0026 7;\n hhh \u0026= ~(7 \u003c\u003c i);\n uint256[8][3][2] memory tables_ = tables;\n uint256 aa = mulmod(\n wd,\n tables_[1][0][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ab = mulmod(\n ws,\n tables_[1][1][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ac = mulmod(\n wt,\n tables_[1][2][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n vvu = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n vvy = ab + aa;\n vvv = wz + ac;\n }\n if (i == 0) {\n uint256 ws;\n uint256 wd;\n uint256 wz;\n uint256 wt;\n {\n uint256 wx = mulmod(\n vvx,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 wy = mulmod(\n vvy,\n vvu,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n ws = wy + wx;\n wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n wz = mulmod(\n vvu,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n wt = mulmod(\n vvx,\n vvy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n uint256 j = hhh \u0026 7;\n uint256[8][3][2] memory tables_ = tables;\n uint256 aa = mulmod(\n wd,\n tables_[1][0][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ab = mulmod(\n ws,\n tables_[1][1][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 ac = mulmod(\n wt,\n tables_[1][2][j],\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n vvu = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n vvy = ab + aa;\n vvv = wz + ac;\n break;\n }\n {\n uint256 xx = mulmod(\n vvx,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy = mulmod(\n vvy,\n vvu,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz = mulmod(\n vvu,\n vvv,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xx2 = mulmod(\n xx,\n xx,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 yy2 = mulmod(\n yy,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 xxyy = mulmod(\n xx,\n yy,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n uint256 zz2 = mulmod(\n zz,\n zz,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n vvx = xxyy + xxyy;\n vvu = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed;\n vvy = xx2 + yy2;\n vvv = addmod(\n zz2 + zz2,\n 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - vvu,\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n }\n }\n vx = vvx;\n vu = vvu;\n vy = vvy;\n vv = vvv;\n }\n // Step 5: compare the points\n (uint256 vi, uint256 vj) = pow22501(\n mulmod(vu, vv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed)\n );\n vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n vi = mulmod(vi, vj, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);\n vx = mulmod(\n vx,\n mulmod(vi, vv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n vy = mulmod(\n vy,\n mulmod(vi, vu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),\n 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed\n );\n bytes32 vr = bytes32(vy | (vx \u003c\u003c 255));\n vr = bytes32(\n ((uint256(vr) \u0026 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) \u003c\u003c 8) |\n ((uint256(vr) \u0026 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) \u003e\u003e 8)\n );\n vr = bytes32(\n ((uint256(vr) \u0026 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) \u003c\u003c 16) |\n ((uint256(vr) \u0026 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) \u003e\u003e 16)\n );\n vr = bytes32(\n ((uint256(vr) \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) \u003c\u003c 32) |\n ((uint256(vr) \u0026 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) \u003e\u003e 32)\n );\n vr = bytes32(\n ((uint256(vr) \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) \u003c\u003c 64) |\n ((uint256(vr) \u0026 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) \u003e\u003e 64)\n );\n vr = bytes32((uint256(vr) \u003c\u003c 128) | (uint256(vr) \u003e\u003e 128));\n return vr == r;\n }\n }\n}\n"},"INearBridge.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\ninterface INearBridge {\n event BlockHashAdded(uint64 indexed height, bytes32 blockHash);\n\n event BlockHashReverted(uint64 indexed height, bytes32 blockHash);\n\n function blockHashes(uint64 blockNumber) external view returns (bytes32);\n\n function blockMerkleRoots(uint64 blockNumber) external view returns (bytes32);\n\n function balanceOf(address wallet) external view returns (uint256);\n\n function deposit() external payable;\n\n function withdraw() external;\n\n function initWithValidators(bytes calldata initialValidators) external;\n\n function initWithBlock(bytes calldata data) external;\n\n function addLightClientBlock(bytes calldata data) external;\n\n function challenge(address payable receiver, uint256 signatureIndex) external;\n\n function checkBlockProducerSignatureInHead(uint256 signatureIndex) external view returns (bool);\n}\n"},"NearBridge.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\nimport \"./AdminControlled.sol\";\nimport \"./INearBridge.sol\";\nimport \"./NearDecoder.sol\";\nimport \"./Ed25519.sol\";\n\ncontract NearBridge is INearBridge, AdminControlled {\n using Borsh for Borsh.Data;\n using NearDecoder for Borsh.Data;\n\n // Assumed to be even and to not exceed 256.\n uint constant MAX_BLOCK_PRODUCERS = 100;\n\n struct Epoch {\n bytes32 epochId;\n uint numBPs;\n bytes32[MAX_BLOCK_PRODUCERS] keys;\n bytes32[MAX_BLOCK_PRODUCERS / 2] packedStakes;\n uint256 stakeThreshold;\n }\n\n // Whether the contract was initialized.\n bool public initialized;\n uint256 public lockEthAmount;\n // lockDuration and replaceDuration shouldn\u0027t be extremely big, so adding them to an uint64 timestamp should not overflow uint256.\n uint256 public lockDuration;\n // replaceDuration is in nanoseconds, because it is a difference between NEAR timestamps.\n uint256 public replaceDuration;\n Ed25519 immutable edwards;\n\n Epoch[3] epochs;\n uint curEpoch;\n uint64 curHeight;\n\n // The most recently added block. May still be in its challenge period, so should not be trusted.\n uint64 untrustedHeight;\n uint256 untrustedTimestamp;\n bool untrustedNextEpoch;\n bytes32 untrustedHash;\n bytes32 untrustedMerkleRoot;\n bytes32 untrustedNextHash;\n uint256 untrustedSignatureSet;\n NearDecoder.Signature[MAX_BLOCK_PRODUCERS] untrustedSignatures;\n\n // Address of the account which submitted the last block.\n address lastSubmitter;\n // End of challenge period. If zero, untrusted* fields and lastSubmitter are not meaningful.\n uint public lastValidAt;\n\n mapping(uint64 =\u003e bytes32) blockHashes_;\n mapping(uint64 =\u003e bytes32) blockMerkleRoots_;\n mapping(address =\u003e uint256) public override balanceOf;\n\n constructor(\n Ed25519 ed,\n uint256 lockEthAmount_,\n uint256 lockDuration_,\n uint256 replaceDuration_,\n address admin_,\n uint256 pausedFlags_\n ) AdminControlled(admin_, pausedFlags_) {\n require(replaceDuration_ \u003e lockDuration_ * 1000000000);\n edwards = ed;\n lockEthAmount = lockEthAmount_;\n lockDuration = lockDuration_;\n replaceDuration = replaceDuration_;\n }\n\n uint constant UNPAUSE_ALL = 0;\n uint constant PAUSED_DEPOSIT = 1;\n uint constant PAUSED_WITHDRAW = 2;\n uint constant PAUSED_ADD_BLOCK = 4;\n uint constant PAUSED_CHALLENGE = 8;\n uint constant PAUSED_VERIFY = 16;\n\n function deposit() public payable override pausable(PAUSED_DEPOSIT) {\n require(msg.value == lockEthAmount \u0026\u0026 balanceOf[msg.sender] == 0);\n balanceOf[msg.sender] = msg.value;\n }\n\n function withdraw() public override pausable(PAUSED_WITHDRAW) {\n require(msg.sender != lastSubmitter || block.timestamp \u003e= lastValidAt);\n uint amount = balanceOf[msg.sender];\n require(amount != 0);\n balanceOf[msg.sender] = 0;\n payable(msg.sender).transfer(amount);\n }\n\n function challenge(address payable receiver, uint signatureIndex) public override pausable(PAUSED_CHALLENGE) {\n require(block.timestamp \u003c lastValidAt, \"No block can be challenged at this time\");\n require(!checkBlockProducerSignatureInHead(signatureIndex), \"Can\u0027t challenge valid signature\");\n\n balanceOf[lastSubmitter] = balanceOf[lastSubmitter] - lockEthAmount;\n receiver.transfer(lockEthAmount / 2);\n lastValidAt = 0;\n }\n\n function checkBlockProducerSignatureInHead(uint signatureIndex) public view override returns (bool) {\n // Shifting by a number \u003e= 256 returns zero.\n require((untrustedSignatureSet \u0026 (1 \u003c\u003c signatureIndex)) != 0, \"No such signature\");\n unchecked {\n Epoch storage untrustedEpoch = epochs[untrustedNextEpoch ? (curEpoch + 1) % 3 : curEpoch];\n NearDecoder.Signature storage signature = untrustedSignatures[signatureIndex];\n bytes memory message = abi.encodePacked(\n uint8(0),\n untrustedNextHash,\n Utils.swapBytes8(untrustedHeight + 2),\n bytes23(0)\n );\n (bytes32 arg1, bytes9 arg2) = abi.decode(message, (bytes32, bytes9));\n return edwards.check(untrustedEpoch.keys[signatureIndex], signature.r, signature.s, arg1, arg2);\n }\n }\n\n // The first part of initialization -- setting the validators of the current epoch.\n function initWithValidators(bytes memory data) public override onlyAdmin {\n require(!initialized \u0026\u0026 epochs[0].numBPs == 0, \"Wrong initialization stage\");\n\n Borsh.Data memory borsh = Borsh.from(data);\n NearDecoder.BlockProducer[] memory initialValidators = borsh.decodeBlockProducers();\n borsh.done();\n\n setBlockProducers(initialValidators, epochs[0]);\n }\n\n // The second part of the initialization -- setting the current head.\n function initWithBlock(bytes memory data) public override onlyAdmin {\n require(!initialized \u0026\u0026 epochs[0].numBPs != 0, \"Wrong initialization stage\");\n initialized = true;\n\n Borsh.Data memory borsh = Borsh.from(data);\n NearDecoder.LightClientBlock memory nearBlock = borsh.decodeLightClientBlock();\n borsh.done();\n\n require(nearBlock.next_bps.some, \"Initialization block must contain next_bps\");\n\n curHeight = nearBlock.inner_lite.height;\n epochs[0].epochId = nearBlock.inner_lite.epoch_id;\n epochs[1].epochId = nearBlock.inner_lite.next_epoch_id;\n blockHashes_[nearBlock.inner_lite.height] = nearBlock.hash;\n blockMerkleRoots_[nearBlock.inner_lite.height] = nearBlock.inner_lite.block_merkle_root;\n setBlockProducers(nearBlock.next_bps.blockProducers, epochs[1]);\n }\n\n struct BridgeState {\n uint currentHeight; // Height of the current confirmed block\n // If there is currently no unconfirmed block, the last three fields are zero.\n uint nextTimestamp; // Timestamp of the current unconfirmed block\n uint nextValidAt; // Timestamp when the current unconfirmed block will be confirmed\n uint numBlockProducers; // Number of block producers for the current unconfirmed block\n }\n\n function bridgeState() public view returns (BridgeState memory res) {\n if (block.timestamp \u003c lastValidAt) {\n res.currentHeight = curHeight;\n res.nextTimestamp = untrustedTimestamp;\n res.nextValidAt = lastValidAt;\n unchecked {\n res.numBlockProducers = epochs[untrustedNextEpoch ? (curEpoch + 1) % 3 : curEpoch].numBPs;\n }\n } else {\n res.currentHeight = lastValidAt == 0 ? curHeight : untrustedHeight;\n }\n }\n\n function addLightClientBlock(bytes memory data) public override pausable(PAUSED_ADD_BLOCK) {\n require(initialized, \"Contract is not initialized\");\n require(balanceOf[msg.sender] \u003e= lockEthAmount, \"Balance is not enough\");\n\n Borsh.Data memory borsh = Borsh.from(data);\n NearDecoder.LightClientBlock memory nearBlock = borsh.decodeLightClientBlock();\n borsh.done();\n\n unchecked {\n // Commit the previous block, or make sure that it is OK to replace it.\n if (block.timestamp \u003c lastValidAt) {\n require(\n nearBlock.inner_lite.timestamp \u003e= untrustedTimestamp + replaceDuration,\n \"Can only replace with a sufficiently newer block\"\n );\n } else if (lastValidAt != 0) {\n curHeight = untrustedHeight;\n if (untrustedNextEpoch) {\n curEpoch = (curEpoch + 1) % 3;\n }\n lastValidAt = 0;\n\n blockHashes_[curHeight] = untrustedHash;\n blockMerkleRoots_[curHeight] = untrustedMerkleRoot;\n }\n\n // Check that the new block\u0027s height is greater than the current one\u0027s.\n require(nearBlock.inner_lite.height \u003e curHeight, \"New block must have higher height\");\n\n // Check that the new block is from the same epoch as the current one, or from the next one.\n bool fromNextEpoch;\n if (nearBlock.inner_lite.epoch_id == epochs[curEpoch].epochId) {\n fromNextEpoch = false;\n } else if (nearBlock.inner_lite.epoch_id == epochs[(curEpoch + 1) % 3].epochId) {\n fromNextEpoch = true;\n } else {\n revert(\"Epoch id of the block is not valid\");\n }\n\n // Check that the new block is signed by more than 2/3 of the validators.\n Epoch storage thisEpoch = epochs[fromNextEpoch ? (curEpoch + 1) % 3 : curEpoch];\n // Last block in the epoch might contain extra approvals that light client can ignore.\n require(nearBlock.approvals_after_next.length \u003e= thisEpoch.numBPs, \"Approval list is too short\");\n // The sum of uint128 values cannot overflow.\n uint256 votedFor = 0;\n for ((uint i, uint cnt) = (0, thisEpoch.numBPs); i != cnt; ++i) {\n bytes32 stakes = thisEpoch.packedStakes[i \u003e\u003e 1];\n if (nearBlock.approvals_after_next[i].some) {\n votedFor += uint128(bytes16(stakes));\n }\n if (++i == cnt) {\n break;\n }\n if (nearBlock.approvals_after_next[i].some) {\n votedFor += uint128(uint256(stakes));\n }\n }\n require(votedFor \u003e thisEpoch.stakeThreshold, \"Too few approvals\");\n\n // If the block is from the next epoch, make sure that next_bps is supplied and has a correct hash.\n if (fromNextEpoch) {\n require(nearBlock.next_bps.some, \"Next next_bps should not be None\");\n require(\n nearBlock.next_bps.hash == nearBlock.inner_lite.next_bp_hash,\n \"Hash of block producers does not match\"\n );\n }\n\n untrustedHeight = nearBlock.inner_lite.height;\n untrustedTimestamp = nearBlock.inner_lite.timestamp;\n untrustedHash = nearBlock.hash;\n untrustedMerkleRoot = nearBlock.inner_lite.block_merkle_root;\n untrustedNextHash = nearBlock.next_hash;\n\n uint256 signatureSet = 0;\n for ((uint i, uint cnt) = (0, thisEpoch.numBPs); i \u003c cnt; i++) {\n NearDecoder.OptionalSignature memory approval = nearBlock.approvals_after_next[i];\n if (approval.some) {\n signatureSet |= 1 \u003c\u003c i;\n untrustedSignatures[i] = approval.signature;\n }\n }\n untrustedSignatureSet = signatureSet;\n untrustedNextEpoch = fromNextEpoch;\n if (fromNextEpoch) {\n Epoch storage nextEpoch = epochs[(curEpoch + 2) % 3];\n nextEpoch.epochId = nearBlock.inner_lite.next_epoch_id;\n setBlockProducers(nearBlock.next_bps.blockProducers, nextEpoch);\n }\n lastSubmitter = msg.sender;\n lastValidAt = block.timestamp + lockDuration;\n }\n }\n\n function setBlockProducers(NearDecoder.BlockProducer[] memory src, Epoch storage epoch) internal {\n uint cnt = src.length;\n require(cnt \u003c= MAX_BLOCK_PRODUCERS, \"It is not expected having that many block producers for the provided block\");\n epoch.numBPs = cnt;\n unchecked {\n for (uint i = 0; i \u003c cnt; i++) {\n epoch.keys[i] = src[i].publicKey.k;\n }\n uint256 totalStake = 0; // Sum of uint128, can\u0027t be too big.\n for (uint i = 0; i != cnt; ++i) {\n uint128 stake1 = src[i].stake;\n totalStake += stake1;\n if (++i == cnt) {\n epoch.packedStakes[i \u003e\u003e 1] = bytes32(bytes16(stake1));\n break;\n }\n uint128 stake2 = src[i].stake;\n totalStake += stake2;\n epoch.packedStakes[i \u003e\u003e 1] = bytes32(uint256(bytes32(bytes16(stake1))) + stake2);\n }\n epoch.stakeThreshold = (totalStake * 2) / 3;\n }\n }\n\n function blockHashes(uint64 height) public view override pausable(PAUSED_VERIFY) returns (bytes32 res) {\n res = blockHashes_[height];\n if (res == 0 \u0026\u0026 block.timestamp \u003e= lastValidAt \u0026\u0026 lastValidAt != 0 \u0026\u0026 height == untrustedHeight) {\n res = untrustedHash;\n }\n }\n\n function blockMerkleRoots(uint64 height) public view override pausable(PAUSED_VERIFY) returns (bytes32 res) {\n res = blockMerkleRoots_[height];\n if (res == 0 \u0026\u0026 block.timestamp \u003e= lastValidAt \u0026\u0026 lastValidAt != 0 \u0026\u0026 height == untrustedHeight) {\n res = untrustedMerkleRoot;\n }\n }\n}\n"},"NearDecoder.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\nimport \"./Borsh.sol\";\n\nlibrary NearDecoder {\n using Borsh for Borsh.Data;\n using NearDecoder for Borsh.Data;\n\n uint8 constant VALIDATOR_V1 = 0;\n uint8 constant VALIDATOR_V2 = 1;\n\n struct PublicKey {\n bytes32 k;\n }\n\n function decodePublicKey(Borsh.Data memory data) internal pure returns (PublicKey memory res) {\n require(data.decodeU8() == 0, \"Parse error: invalid key type\");\n res.k = data.decodeBytes32();\n }\n\n struct Signature {\n bytes32 r;\n bytes32 s;\n }\n\n function decodeSignature(Borsh.Data memory data) internal pure returns (Signature memory res) {\n require(data.decodeU8() == 0, \"Parse error: invalid signature type\");\n res.r = data.decodeBytes32();\n res.s = data.decodeBytes32();\n }\n\n struct BlockProducer {\n PublicKey publicKey;\n uint128 stake;\n // Flag indicating if this validator proposed to be a chunk-only producer (i.e. cannot become a block producer).\n bool isChunkOnly;\n }\n\n function decodeBlockProducer(Borsh.Data memory data) internal pure returns (BlockProducer memory res) {\n uint8 validator_version = data.decodeU8();\n data.skipBytes();\n res.publicKey = data.decodePublicKey();\n res.stake = data.decodeU128();\n if (validator_version == VALIDATOR_V2) {\n res.isChunkOnly = data.decodeU8() != 0;\n } else {\n res.isChunkOnly = false;\n }\n }\n\n function decodeBlockProducers(Borsh.Data memory data) internal pure returns (BlockProducer[] memory res) {\n uint length = data.decodeU32();\n res = new BlockProducer[](length);\n for (uint i = 0; i \u003c length; i++) {\n res[i] = data.decodeBlockProducer();\n }\n }\n\n struct OptionalBlockProducers {\n bool some;\n BlockProducer[] blockProducers;\n bytes32 hash; // Additional computable element\n }\n\n function decodeOptionalBlockProducers(Borsh.Data memory data)\n internal\n view\n returns (OptionalBlockProducers memory res)\n {\n res.some = data.decodeBool();\n if (res.some) {\n uint start = data.ptr;\n res.blockProducers = data.decodeBlockProducers();\n res.hash = Utils.sha256Raw(start, data.ptr - start);\n }\n }\n\n struct OptionalSignature {\n bool some;\n Signature signature;\n }\n\n function decodeOptionalSignature(Borsh.Data memory data) internal pure returns (OptionalSignature memory res) {\n res.some = data.decodeBool();\n if (res.some) {\n res.signature = data.decodeSignature();\n }\n }\n\n struct BlockHeaderInnerLite {\n uint64 height; // Height of this block since the genesis block (height 0).\n bytes32 epoch_id; // Epoch start hash of this block\u0027s epoch. Used for retrieving validator information\n bytes32 next_epoch_id;\n bytes32 prev_state_root; // Root hash of the state at the previous block.\n bytes32 outcome_root; // Root of the outcomes of transactions and receipts.\n uint64 timestamp; // Timestamp at which the block was built.\n bytes32 next_bp_hash; // Hash of the next epoch block producers set\n bytes32 block_merkle_root;\n bytes32 hash; // Additional computable element\n }\n\n function decodeBlockHeaderInnerLite(Borsh.Data memory data)\n internal\n view\n returns (BlockHeaderInnerLite memory res)\n {\n res.hash = data.peekSha256(208);\n res.height = data.decodeU64();\n res.epoch_id = data.decodeBytes32();\n res.next_epoch_id = data.decodeBytes32();\n res.prev_state_root = data.decodeBytes32();\n res.outcome_root = data.decodeBytes32();\n res.timestamp = data.decodeU64();\n res.next_bp_hash = data.decodeBytes32();\n res.block_merkle_root = data.decodeBytes32();\n }\n\n struct LightClientBlock {\n bytes32 prev_block_hash;\n bytes32 next_block_inner_hash;\n BlockHeaderInnerLite inner_lite;\n bytes32 inner_rest_hash;\n OptionalBlockProducers next_bps;\n OptionalSignature[] approvals_after_next;\n bytes32 hash;\n bytes32 next_hash;\n }\n\n function decodeLightClientBlock(Borsh.Data memory data) internal view returns (LightClientBlock memory res) {\n res.prev_block_hash = data.decodeBytes32();\n res.next_block_inner_hash = data.decodeBytes32();\n res.inner_lite = data.decodeBlockHeaderInnerLite();\n res.inner_rest_hash = data.decodeBytes32();\n res.next_bps = data.decodeOptionalBlockProducers();\n\n uint length = data.decodeU32();\n res.approvals_after_next = new OptionalSignature[](length);\n for (uint i = 0; i \u003c length; i++) {\n res.approvals_after_next[i] = data.decodeOptionalSignature();\n }\n\n res.hash = sha256(\n abi.encodePacked(sha256(abi.encodePacked(res.inner_lite.hash, res.inner_rest_hash)), res.prev_block_hash)\n );\n\n res.next_hash = sha256(abi.encodePacked(res.next_block_inner_hash, res.hash));\n }\n}\n"},"Utils.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8;\n\nlibrary Utils {\n function swapBytes2(uint16 v) internal pure returns (uint16) {\n return (v \u003c\u003c 8) | (v \u003e\u003e 8);\n }\n\n function swapBytes4(uint32 v) internal pure returns (uint32) {\n v = ((v \u0026 0x00ff00ff) \u003c\u003c 8) | ((v \u0026 0xff00ff00) \u003e\u003e 8);\n return (v \u003c\u003c 16) | (v \u003e\u003e 16);\n }\n\n function swapBytes8(uint64 v) internal pure returns (uint64) {\n v = ((v \u0026 0x00ff00ff00ff00ff) \u003c\u003c 8) | ((v \u0026 0xff00ff00ff00ff00) \u003e\u003e 8);\n v = ((v \u0026 0x0000ffff0000ffff) \u003c\u003c 16) | ((v \u0026 0xffff0000ffff0000) \u003e\u003e 16);\n return (v \u003c\u003c 32) | (v \u003e\u003e 32);\n }\n\n function swapBytes16(uint128 v) internal pure returns (uint128) {\n v = ((v \u0026 0x00ff00ff00ff00ff00ff00ff00ff00ff) \u003c\u003c 8) | ((v \u0026 0xff00ff00ff00ff00ff00ff00ff00ff00) \u003e\u003e 8);\n v = ((v \u0026 0x0000ffff0000ffff0000ffff0000ffff) \u003c\u003c 16) | ((v \u0026 0xffff0000ffff0000ffff0000ffff0000) \u003e\u003e 16);\n v = ((v \u0026 0x00000000ffffffff00000000ffffffff) \u003c\u003c 32) | ((v \u0026 0xffffffff00000000ffffffff00000000) \u003e\u003e 32);\n return (v \u003c\u003c 64) | (v \u003e\u003e 64);\n }\n\n function swapBytes32(uint256 v) internal pure returns (uint256) {\n v =\n ((v \u0026 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff) \u003c\u003c 8) |\n ((v \u0026 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00) \u003e\u003e 8);\n v =\n ((v \u0026 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff) \u003c\u003c 16) |\n ((v \u0026 0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000) \u003e\u003e 16);\n v =\n ((v \u0026 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff) \u003c\u003c 32) |\n ((v \u0026 0xffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000) \u003e\u003e 32);\n v =\n ((v \u0026 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff) \u003c\u003c 64) |\n ((v \u0026 0xffffffffffffffff0000000000000000ffffffffffffffff0000000000000000) \u003e\u003e 64);\n return (v \u003c\u003c 128) | (v \u003e\u003e 128);\n }\n\n function readMemory(uint ptr) internal pure returns (uint res) {\n assembly {\n res := mload(ptr)\n }\n }\n\n function writeMemory(uint ptr, uint value) internal pure {\n assembly {\n mstore(ptr, value)\n }\n }\n\n function memoryToBytes(uint ptr, uint length) internal pure returns (bytes memory res) {\n if (length != 0) {\n assembly {\n // 0x40 is the address of free memory pointer.\n res := mload(0x40)\n let end := add(\n res,\n and(add(length, 63), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)\n )\n // end = res + 32 + 32 * ceil(length / 32).\n mstore(0x40, end)\n mstore(res, length)\n let destPtr := add(res, 32)\n // prettier-ignore\n for { } 1 { } {\n mstore(destPtr, mload(ptr))\n destPtr := add(destPtr, 32)\n if eq(destPtr, end) {\n break\n }\n ptr := add(ptr, 32)\n }\n }\n }\n }\n\n function keccak256Raw(uint ptr, uint length) internal pure returns (bytes32 res) {\n assembly {\n res := keccak256(ptr, length)\n }\n }\n\n function sha256Raw(uint ptr, uint length) internal view returns (bytes32 res) {\n assembly {\n // 2 is the address of SHA256 precompiled contract.\n // First 64 bytes of memory can be used as scratch space.\n let ret := staticcall(gas(), 2, ptr, length, 0, 32)\n // If the call to SHA256 precompile ran out of gas, burn any gas that remains.\n // prettier-ignore\n for { } iszero(ret) { } { }\n res := mload(0)\n }\n }\n}\n"}}