Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract contains unverified libraries: Ed25519
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
FrameMessageValidator
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {IKeyRegistry} from "farcaster/interfaces/IKeyRegistry.sol"; import { MessageDataCodec, MessageData, MessageCodec, Message, SignatureScheme, MessageType } from "./protobufs/Message.sol"; import {Blake3} from "farcaster-solidity/libraries/Blake3.sol"; import {Ed25519} from "farcaster-solidity/libraries/Ed25519.sol"; contract FrameMessageValidator { error InvalidMessage(); error InvalidMessageHash(); error InvalidSignature(); error InvalidKey(); error InvalidMessageType(); error InvalidSignatureScheme(); error InvalidUrl(); error InvalidButtonIndex(); address constant keyRegistry = 0x00000000Fc1237824fb747aBDE0FF18990E59b7e; function validateMessage(bytes memory message) public view returns (Message memory) { // Decode message (bool msgValid,, Message memory decodedMessage) = MessageCodec.decode(0, message, uint64(message.length)); // Message must be valid if (!msgValid) revert InvalidMessage(); { // re-encode message data bytes memory messageData = MessageDataCodec.encode(decodedMessage.data); // Calculate Blake3 hash of FC message (first 20 bytes) bytes memory messageHash = Blake3.hash(messageData, 20); // Message hash must be valid if (keccak256(messageHash) != keccak256(decodedMessage.hash_)) revert InvalidMessageHash(); } { bytes32 sig_r; bytes32 sig_s; bytes memory signature = decodedMessage.signature; assembly { sig_r := mload(add(signature, 32)) sig_s := mload(add(signature, 64)) } // Verify signature bool sigValid = Ed25519.verify(bytes32(decodedMessage.signer), sig_r, sig_s, decodedMessage.hash_); // Signature must be valid if (!sigValid) revert InvalidSignature(); } // Public key must be valid for fid IKeyRegistry.KeyData memory data = IKeyRegistry(keyRegistry).keyDataOf(decodedMessage.data.fid, decodedMessage.signer); if (data.state != IKeyRegistry.KeyState.ADDED) revert InvalidKey(); // Validate frame message (see: https://docs.farcaster.xyz/reference/frames/spec#frame-signature) // Frame messages must use ed25519 signature scheme if (decodedMessage.signature_scheme != SignatureScheme.SIGNATURE_SCHEME_ED25519) { revert InvalidSignatureScheme(); } // Message must be a frame action if (decodedMessage.data.type_ != MessageType.MESSAGE_TYPE_FRAME_ACTION) revert InvalidMessageType(); // Url length must be <= 256 bytes if (decodedMessage.data.frame_action_body.url.length > 256) revert InvalidUrl(); // Button index must be between 1 and 4 uint32 buttonIndex = decodedMessage.data.frame_action_body.button_index; if (buttonIndex < 1 || buttonIndex > 4) revert InvalidButtonIndex(); return decodedMessage; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {IMetadataValidator} from "./IMetadataValidator.sol"; import {IdRegistryLike} from "./IdRegistryLike.sol"; interface IKeyRegistry { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ /// @dev Revert if a key violates KeyState transition rules. error InvalidState(); /// @dev Revert if adding a key exceeds the maximum number of allowed keys per fid. error ExceedsMaximum(); /// @dev Revert if a validator has not been registered for this keyType and metadataType. error ValidatorNotFound(uint32 keyType, uint8 metadataType); /// @dev Revert if metadata validation failed. error InvalidMetadata(); /// @dev Revert if the admin sets a validator for keyType 0. error InvalidKeyType(); /// @dev Revert if the admin sets a validator for metadataType 0. error InvalidMetadataType(); /// @dev Revert if the caller does not have the authority to perform the action. error Unauthorized(); /// @dev Revert if the owner sets maxKeysPerFid equal to or below its current value. error InvalidMaxKeys(); /// @dev Revert when the gateway dependency is permanently frozen. error GatewayFrozen(); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /** * @dev Emit an event when an admin or fid adds a new key. * * Hubs listen for this, validate that keyBytes is an EdDSA pub key and keyType == 1 and * add keyBytes to its SignerStore. Messages signed by keyBytes with `fid` are now valid * and accepted over gossip, sync and client apis. Hubs assume the invariants: * * 1. Add(fid, ..., key, keyBytes, ...) cannot emit if there is an earlier emit with * Add(fid, ..., key, keyBytes, ...) and no AdminReset(fid, key, keyBytes) inbetween. * * 2. Add(fid, ..., key, keyBytes, ...) cannot emit if there is an earlier emit with * Remove(fid, key, keyBytes). * * 3. For all Add(..., ..., key, keyBytes, ...), key = keccak(keyBytes) * * @param fid The fid associated with the key. * @param keyType The type of the key. * @param key The key being registered. (indexed as hash) * @param keyBytes The bytes of the key being registered. * @param metadataType The type of the metadata. * @param metadata Metadata about the key. */ event Add( uint256 indexed fid, uint32 indexed keyType, bytes indexed key, bytes keyBytes, uint8 metadataType, bytes metadata ); /** * @dev Emit an event when an fid removes an added key. * * Hubs listen for this, validate that keyType == 1 and keyBytes exists in its SignerStore. * keyBytes is marked as removed, messages signed by keyBytes with `fid` are invalid, * dropped immediately and no longer accepted. Hubs assume the invariants: * * 1. Remove(fid, key, keyBytes) cannot emit if there is no earlier emit with * Add(fid, ..., key, keyBytes, ...) * * 2. Remove(fid, key, keyBytes) cannot emit if there is an earlier emit with * Remove(fid, key, keyBytes) * * 3. For all Remove(..., key, keyBytes), key = keccak(keyBytes) * * @param fid The fid associated with the key. * @param key The key being registered. (indexed as hash) * @param keyBytes The bytes of the key being registered. */ event Remove(uint256 indexed fid, bytes indexed key, bytes keyBytes); /** * @dev Emit an event when an admin resets an added key. * * Hubs listen for this, validate that keyType == 1 and that keyBytes exists in its SignerStore. * keyBytes is no longer tracked, messages signed by keyBytes with `fid` are invalid, dropped * immediately and not accepted. Hubs assume the following invariants: * * 1. AdminReset(fid, key, keyBytes) cannot emit unless the most recent event for the fid * was Add(fid, ..., key, keyBytes, ...). * * 2. For all AdminReset(..., key, keyBytes), key = keccak(keyBytes). * * 3. AdminReset() cannot emit after Migrated(). * * @param fid The fid associated with the key. * @param key The key being reset. (indexed as hash) * @param keyBytes The bytes of the key being registered. */ event AdminReset(uint256 indexed fid, bytes indexed key, bytes keyBytes); /** * @dev Emit an event when the admin sets a metadata validator contract for a given * keyType and metadataType. * * @param keyType The numeric keyType associated with this validator. * @param metadataType The metadataType associated with this validator. * @param oldValidator The previous validator contract address. * @param newValidator The new validator contract address. */ event SetValidator(uint32 keyType, uint8 metadataType, address oldValidator, address newValidator); /** * @dev Emit an event when the admin sets a new IdRegistry contract address. * * @param oldIdRegistry The previous IdRegistry address. * @param newIdRegistry The new IdRegistry address. */ event SetIdRegistry(address oldIdRegistry, address newIdRegistry); /** * @dev Emit an event when the admin sets a new KeyGateway address. * * @param oldKeyGateway The previous KeyGateway address. * @param newKeyGateway The new KeyGateway address. */ event SetKeyGateway(address oldKeyGateway, address newKeyGateway); /** * @dev Emit an event when the admin sets a new maximum keys per fid. * * @param oldMax The previous maximum. * @param newMax The new maximum. */ event SetMaxKeysPerFid(uint256 oldMax, uint256 newMax); /** * @dev Emit an event when the contract owner permanently freezes the KeyGateway address. * * @param keyGateway The permanent KeyGateway address. */ event FreezeKeyGateway(address keyGateway); /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ /** * @notice State enumeration for a key in the registry. During migration, an admin can change * the state of any fids key from NULL to ADDED or ADDED to NULL. After migration, an * fid can change the state of a key from NULL to ADDED or ADDED to REMOVED only. * * - NULL: The key is not in the registry. * - ADDED: The key has been added to the registry. * - REMOVED: The key was added to the registry but is now removed. */ enum KeyState { NULL, ADDED, REMOVED } /** * @notice Data about a key. * * @param state The current state of the key. * @param keyType Numeric ID representing the manner in which the key should be used. */ struct KeyData { KeyState state; uint32 keyType; } /** * @dev Struct argument for bulk add function, representing an FID * and its associated keys. * * @param fid Fid associated with provided keys to add. * @param keys Array of BulkAddKey structs, including key and metadata. */ struct BulkAddData { uint256 fid; BulkAddKey[] keys; } /** * @dev Struct argument for bulk add function, representing a key * and its associated metadata. * * @param key Bytes of the signer key. * @param keys Metadata metadata of the signer key. */ struct BulkAddKey { bytes key; bytes metadata; } /** * @dev Struct argument for bulk reset function, representing an FID * and its associated keys. * * @param fid Fid associated with provided keys to reset. * @param keys Array of keys to reset. */ struct BulkResetData { uint256 fid; bytes[] keys; } /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * @notice Contract version specified in the Farcaster protocol version scheme. */ function VERSION() external view returns (string memory); /** * @notice EIP-712 typehash for Remove signatures. */ function REMOVE_TYPEHASH() external view returns (bytes32); /*////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ /** * @notice The IdRegistry contract. */ function idRegistry() external view returns (IdRegistryLike); /** * @notice The KeyGateway address. */ function keyGateway() external view returns (address); /** * @notice Whether the KeyGateway address is permanently frozen. */ function gatewayFrozen() external view returns (bool); /** * @notice Maximum number of keys per fid. */ function maxKeysPerFid() external view returns (uint256); /*////////////////////////////////////////////////////////////// VIEWS //////////////////////////////////////////////////////////////*/ /** * @notice Return number of active keys for a given fid. * * @param fid the fid associated with the keys. * * @return uint256 total number of active keys associated with the fid. */ function totalKeys(uint256 fid, KeyState state) external view returns (uint256); /** * @notice Return key at the given index in the fid's key set. Can be * called to enumerate all active keys for a given fid. * * @param fid the fid associated with the key. * @param index index of the key in the fid's key set. Must be a value * less than totalKeys(fid). Note that because keys are * stored in an underlying enumerable set, the ordering of * keys is not guaranteed to be stable. * * @return bytes Bytes of the key. */ function keyAt(uint256 fid, KeyState state, uint256 index) external view returns (bytes memory); /** * @notice Return an array of all active keys for a given fid. * @dev WARNING: This function will copy the entire key set to memory, * which can be quite expensive. This is intended to be called * offchain with eth_call, not onchain. * * @param fid the fid associated with the keys. * * @return bytes[] Array of all keys. */ function keysOf(uint256 fid, KeyState state) external view returns (bytes[] memory); /** * @notice Return an array of all active keys for a given fid, * paged by index and batch size. * * @param fid The fid associated with the keys. * @param startIdx Start index of lookup. * @param batchSize Number of items to return. * * @return page Array of keys. * @return nextIdx Next index in the set of all keys. */ function keysOf( uint256 fid, KeyState state, uint256 startIdx, uint256 batchSize ) external view returns (bytes[] memory page, uint256 nextIdx); /** * @notice Retrieve state and type data for a given key. * * @param fid The fid associated with the key. * @param key Bytes of the key. * * @return KeyData struct that contains the state and keyType. */ function keyDataOf(uint256 fid, bytes calldata key) external view returns (KeyData memory); /*////////////////////////////////////////////////////////////// REMOVE KEYS //////////////////////////////////////////////////////////////*/ /** * @notice Remove a key associated with the caller's fid, setting the key state to REMOVED. * The key must be in the ADDED state. * * @param key Bytes of the key to remove. */ function remove(bytes calldata key) external; /** * @notice Remove a key on behalf of another fid owner, setting the key state to REMOVED. * caller must supply a valid EIP-712 Remove signature from the fid owner. * * @param fidOwner The fid owner address. * @param key Bytes of the key to remove. * @param deadline Deadline after which the signature expires. * @param sig EIP-712 Remove signature generated by fid owner. */ function removeFor(address fidOwner, bytes calldata key, uint256 deadline, bytes calldata sig) external; /*////////////////////////////////////////////////////////////// PERMISSIONED ACTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Add a key associated with fidOwner's fid, setting the key state to ADDED. * Can only be called by the keyGateway address. * * @param keyType The key's numeric keyType. * @param key Bytes of the key to add. * @param metadataType Metadata type ID. * @param metadata Metadata about the key, which is not stored and only emitted in an event. */ function add( address fidOwner, uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata ) external; /** * @notice Add multiple keys as part of the initial migration. Only callable by the contract owner. * * @param items An array of BulkAddData structs including fid and array of BulkAddKey structs. */ function bulkAddKeysForMigration(BulkAddData[] calldata items) external; /** * @notice Reset multiple keys as part of the initial migration. Only callable by the contract owner. * Reset is not the same as removal: this function sets the key state back to NULL, * rather than REMOVED. This allows the owner to correct any errors in the initial migration until * the grace period expires. * * @param items A list of BulkResetData structs including an fid and array of keys. */ function bulkResetKeysForMigration(BulkResetData[] calldata items) external; /** * @notice Set a metadata validator contract for the given keyType and metadataType. Only callable by owner. * * @param keyType The numeric key type ID associated with this validator. * @param metadataType The numeric metadata type ID associated with this validator. * @param validator Contract implementing IMetadataValidator. */ function setValidator(uint32 keyType, uint8 metadataType, IMetadataValidator validator) external; /** * @notice Set the IdRegistry contract address. Only callable by owner. * * @param _idRegistry The new IdRegistry address. */ function setIdRegistry(address _idRegistry) external; /** * @notice Set the KeyGateway address allowed to add keys. Only callable by owner. * * @param _keyGateway The new KeyGateway address. */ function setKeyGateway(address _keyGateway) external; /** * @notice Permanently freeze the KeyGateway address. Only callable by owner. */ function freezeKeyGateway() external; /** * @notice Set the maximum number of keys allowed per fid. Only callable by owner. * * @param _maxKeysPerFid The new max keys per fid. */ function setMaxKeysPerFid(uint256 _maxKeysPerFid) external; }
// File automatically generated by protoc-gen-sol v0.2.0 // // modified by @jaydenwindle // see: https://github.com/wilsoncusack/frame-verifier/blob/ed8bdb7c0117911be45ea2773080d21c67737385/src/Encoder.sol // see: https://github.com/pavlovdog/farcaster-solidity/blob/e5272a57589c75f17394eba17d527246976154f4/contracts/protobufs/message.proto.sol // // SPDX-License-Identifier: CC0 pragma solidity >=0.6.0 <8.0.0; pragma experimental ABIEncoderV2; import "@lazyledger/protobuf3-solidity-lib/contracts/ProtobufLib.sol"; enum HashScheme { HASH_SCHEME_NONE, HASH_SCHEME_BLAKE3 } enum SignatureScheme { SIGNATURE_SCHEME_NONE, SIGNATURE_SCHEME_ED25519, SIGNATURE_SCHEME_EIP712 } enum MessageType { MESSAGE_TYPE_NONE, MESSAGE_TYPE_CAST_ADD, MESSAGE_TYPE_CAST_REMOVE, MESSAGE_TYPE_REACTION_ADD, MESSAGE_TYPE_REACTION_REMOVE, MESSAGE_TYPE_LINK_ADD, MESSAGE_TYPE_LINK_REMOVE, MESSAGE_TYPE_VERIFICATION_ADD_ETH_ADDRESS, MESSAGE_TYPE_VERIFICATION_REMOVE, DEPRECATED_MESSAGE_TYPE_SIGNER_ADD, DEPRECATED_MESSAGE_TYPE_SIGNER_REMOVE, MESSAGE_TYPE_USER_DATA_ADD, MESSAGE_TYPE_USERNAME_PROOF, MESSAGE_TYPE_FRAME_ACTION } enum FarcasterNetwork { FARCASTER_NETWORK_NONE, FARCASTER_NETWORK_MAINNET, FARCASTER_NETWORK_TESTNET, FARCASTER_NETWORK_DEVNET } enum UserDataType { USER_DATA_TYPE_NONE, USER_DATA_TYPE_PFP, USER_DATA_TYPE_DISPLAY, USER_DATA_TYPE_BIO, EMPTY, USER_DATA_TYPE_URL, USER_DATA_TYPE_USERNAME } enum ReactionType { REACTION_TYPE_NONE, REACTION_TYPE_LIKE, REACTION_TYPE_RECAST } struct Message { MessageData data; bytes hash_; HashScheme hash_scheme; bytes signature; SignatureScheme signature_scheme; bytes signer; bytes data_bytes; } library MessageCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, Message memory) { // Message instance Message memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 7) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 4) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 5) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 6) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 7) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, Message memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 4) { bool success; (success, pos) = decode_4(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 5) { bool success; (success, pos) = decode_5(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 6) { bool success; (success, pos) = decode_6(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 7) { bool success; (success, pos) = decode_7(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // Message.data function decode_1(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } MessageData memory nestedInstance; (success, pos, nestedInstance) = MessageDataCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.data = nestedInstance; return (true, pos); } // Message.hash_ function decode_2(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.hash_ = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.hash_[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // Message.hash_scheme function decode_3(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 1) { return (false, pos); } instance.hash_scheme = HashScheme(v); return (true, pos); } // Message.signature function decode_4(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.signature = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.signature[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // Message.signature_scheme function decode_5(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 2) { return (false, pos); } instance.signature_scheme = SignatureScheme(v); return (true, pos); } // Message.signer function decode_6(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.signer = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.signer[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // Message.data_bytes function decode_7(uint64 pos, bytes memory buf, Message memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.data_bytes = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.data_bytes[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } } struct MessageData { MessageType type_; uint64 fid; uint32 timestamp; FarcasterNetwork network; CastAddBody cast_add_body; bool empty_cast_remove_body; ReactionBody reaction_body; bool empty; VerificationAddEthAddressBody verification_add_eth_address_body; bool empty_verification_remove_body; bool deprecated_signer_add_body; bool user_data_body; bool deprecated_signer_remove_body; LinkBody link_body; bool empty_username_proof_body; FrameActionBody frame_action_body; } library MessageDataCodec { function encode(MessageData memory instance) internal pure returns (bytes memory) { // Omit encoding fields if default value bytes memory type__Key = uint64(instance.type_) != 0 ? ProtobufLib.encode_key(1, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); bytes memory type_ = uint64(instance.type_) != 0 ? ProtobufLib.encode_int32(int32(uint32(instance.type_))) : new bytes(0); bytes memory fid__Key = uint64(instance.fid) != 0 ? ProtobufLib.encode_key(2, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); bytes memory fid = uint64(instance.fid) != 0 ? ProtobufLib.encode_uint64(instance.fid) : new bytes(0); bytes memory timestamp__Key = uint64(instance.timestamp) != 0 ? ProtobufLib.encode_key(3, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); bytes memory timestamp = uint64(instance.timestamp) != 0 ? ProtobufLib.encode_uint32(instance.timestamp) : new bytes(0); bytes memory network__Key = uint64(instance.network) != 0 ? ProtobufLib.encode_key(4, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); bytes memory network = uint64(instance.network) != 0 ? ProtobufLib.encode_int32(int32(uint32(instance.network))) : new bytes(0); // Encode frame_action_body FrameActionBodyCodec.FrameActionBody__Encoded__Nested memory frame_action_body = FrameActionBodyCodec.encodeNested(16, instance.frame_action_body); bytes memory frame_action_body__Encoded = abi.encodePacked(frame_action_body.key, frame_action_body.length, frame_action_body.nestedInstance); // Use abi.encodePacked for efficient concatenation return abi.encodePacked( type__Key, type_, fid__Key, fid, timestamp__Key, timestamp, network__Key, network, frame_action_body__Encoded ); } function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, MessageData memory) { // Message instance MessageData memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 16) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 4) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 5) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 6) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 7) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 8) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 9) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 10) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 11) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 12) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 13) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 14) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 15) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 16) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, MessageData memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 4) { bool success; (success, pos) = decode_4(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 5) { bool success; (success, pos) = decode_5(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 6) { bool success; (success, pos) = decode_6(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 7) { bool success; (success, pos) = decode_7(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 8) { bool success; (success, pos) = decode_8(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 9) { bool success; (success, pos) = decode_9(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 10) { bool success; (success, pos) = decode_10(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 11) { bool success; (success, pos) = decode_11(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 12) { bool success; (success, pos) = decode_12(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 13) { bool success; (success, pos) = decode_13(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 14) { bool success; (success, pos) = decode_14(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 15) { bool success; (success, pos) = decode_15(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 16) { bool success; (success, pos) = decode_16(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // MessageData.type_ function decode_1(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 13) { return (false, pos); } instance.type_ = MessageType(v); return (true, pos); } // MessageData.fid function decode_2(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.fid = v; return (true, pos); } // MessageData.timestamp function decode_3(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.timestamp = v; return (true, pos); } // MessageData.network function decode_4(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 3) { return (false, pos); } instance.network = FarcasterNetwork(v); return (true, pos); } // MessageData.cast_add_body function decode_5(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } CastAddBody memory nestedInstance; (success, pos, nestedInstance) = CastAddBodyCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.cast_add_body = nestedInstance; return (true, pos); } // MessageData.empty_cast_remove_body function decode_6(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.empty_cast_remove_body = v; return (true, pos); } // MessageData.reaction_body function decode_7(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } ReactionBody memory nestedInstance; (success, pos, nestedInstance) = ReactionBodyCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.reaction_body = nestedInstance; return (true, pos); } // MessageData.empty function decode_8(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.empty = v; return (true, pos); } // MessageData.verification_add_eth_address_body function decode_9(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } VerificationAddEthAddressBody memory nestedInstance; (success, pos, nestedInstance) = VerificationAddEthAddressBodyCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.verification_add_eth_address_body = nestedInstance; return (true, pos); } // MessageData.empty_verification_remove_body function decode_10(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.empty_verification_remove_body = v; return (true, pos); } // MessageData.deprecated_signer_add_body function decode_11(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.deprecated_signer_add_body = v; return (true, pos); } // MessageData.user_data_body function decode_12(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.user_data_body = v; return (true, pos); } // MessageData.deprecated_signer_remove_body function decode_13(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.deprecated_signer_remove_body = v; return (true, pos); } // MessageData.link_body function decode_14(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } LinkBody memory nestedInstance; (success, pos, nestedInstance) = LinkBodyCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.link_body = nestedInstance; return (true, pos); } // MessageData.empty_username_proof_body function decode_15(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; bool v; (success, pos, v) = ProtobufLib.decode_bool(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == false) { return (false, pos); } instance.empty_username_proof_body = v; return (true, pos); } // MessageData.frame_action_body function decode_16(uint64 pos, bytes memory buf, MessageData memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } FrameActionBody memory nestedInstance; (success, pos, nestedInstance) = FrameActionBodyCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.frame_action_body = nestedInstance; return (true, pos); } } struct UserDataBody { UserDataType type_; string value; } library UserDataBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, UserDataBody memory) { // Message instance UserDataBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 2) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, UserDataBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // UserDataBody.type_ function decode_1(uint64 pos, bytes memory buf, UserDataBody memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 6) { return (false, pos); } instance.type_ = UserDataType(v); return (true, pos); } // UserDataBody.value function decode_2(uint64 pos, bytes memory buf, UserDataBody memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.value = v; return (true, pos); } } struct Embed { string url; CastId cast_id; } library EmbedCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, Embed memory) { // Message instance Embed memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 2) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, Embed memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // Embed.url function decode_1(uint64 pos, bytes memory buf, Embed memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.url = v; return (true, pos); } // Embed.cast_id function decode_2(uint64 pos, bytes memory buf, Embed memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } CastId memory nestedInstance; (success, pos, nestedInstance) = CastIdCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.cast_id = nestedInstance; return (true, pos); } } struct CastAddBody { string embeds_deprecated; uint64[] mentions; CastId parent_cast_id; string text; uint32[] mentions_positions; Embed[] embeds; string parent_url; } library CastAddBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, CastAddBody memory) { // Message instance CastAddBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 7) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 4) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 5) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 6) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 7) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, CastAddBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 4) { bool success; (success, pos) = decode_4(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 5) { bool success; (success, pos) = decode_5(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 6) { bool success; (success, pos) = decode_6(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 7) { bool success; (success, pos) = decode_7(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // CastAddBody.embeds_deprecated function decode_1(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.embeds_deprecated = v; return (true, pos); } // CastAddBody.mentions function decode_2(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_length_delimited(pos, buf); if (!success) { return (false, pos); } // Empty packed array must be omitted if (len == 0) { return (false, pos); } uint64 initial_pos = pos; // Sanity checks if (pos + len < pos) { return (false, pos); } // Do one pass to count the number of elements uint64 cnt = 0; while (pos - initial_pos < len) { uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } cnt += 1; } // Allocated memory instance.mentions = new uint64[](cnt); // Now actually parse the elements pos = initial_pos; for (uint64 i = 0; i < cnt; i++) { uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } instance.mentions[i] = v; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos); } return (true, pos); } // CastAddBody.parent_cast_id function decode_3(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } CastId memory nestedInstance; (success, pos, nestedInstance) = CastIdCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.parent_cast_id = nestedInstance; return (true, pos); } // CastAddBody.text function decode_4(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.text = v; return (true, pos); } // CastAddBody.mentions_positions function decode_5(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_length_delimited(pos, buf); if (!success) { return (false, pos); } // Empty packed array must be omitted if (len == 0) { return (false, pos); } uint64 initial_pos = pos; // Sanity checks if (pos + len < pos) { return (false, pos); } // Do one pass to count the number of elements uint64 cnt = 0; while (pos - initial_pos < len) { uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } cnt += 1; } // Allocated memory instance.mentions_positions = new uint32[](cnt); // Now actually parse the elements pos = initial_pos; for (uint64 i = 0; i < cnt; i++) { uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } instance.mentions_positions[i] = v; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos); } return (true, pos); } // CastAddBody.embeds function decode_6(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 initial_pos = pos; // Do one pass to count the number of elements uint64 cnt = 0; while (pos < buf.length) { uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Sanity checks if (pos + len < pos) { return (false, pos); } pos += len; cnt += 1; if (pos >= buf.length) { break; } // Decode next key uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos); } // Check if the field number is different if (field_number != 6) { break; } } // Allocated memory instance.embeds = new Embed[](cnt); // Now actually parse the elements pos = initial_pos; for (uint64 i = 0; i < cnt; i++) { uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } initial_pos = pos; Embed memory nestedInstance; (success, pos, nestedInstance) = EmbedCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.embeds[i] = nestedInstance; // Skip over next key, reuse len if (i < cnt - 1) { (success, pos, len) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } } } return (true, pos); } // CastAddBody.parent_url function decode_7(uint64 pos, bytes memory buf, CastAddBody memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.parent_url = v; return (true, pos); } } struct CastRemoveBody { bytes target_hash; } library CastRemoveBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, CastRemoveBody memory) { // Message instance CastRemoveBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 1) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, CastRemoveBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // CastRemoveBody.target_hash function decode_1(uint64 pos, bytes memory buf, CastRemoveBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.target_hash = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.target_hash[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } } struct CastId { uint64 fid; bytes hash_; } library CastIdCodec { // Holds encoded version of nested message struct CastId__Encoded__Nested { bytes key; bytes length; bytes nestedInstance; } function encode(CastId memory instance) internal pure returns (bytes memory) { bytes memory fid__Key = uint64(instance.fid) != 0 ? ProtobufLib.encode_key(1, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); bytes memory fid = uint64(instance.fid) != 0 ? ProtobufLib.encode_uint64(instance.fid) : new bytes(0); bytes memory hash__Key = instance.hash_.length > 0 ? ProtobufLib.encode_key(2, uint64(ProtobufLib.WireType.LengthDelimited)) : new bytes(0); bytes memory hash__Length = instance.hash_.length > 0 ? ProtobufLib.encode_uint64(uint64(instance.hash_.length)) : new bytes(0); bytes memory hash = instance.hash_.length > 0 ? bytes(instance.hash_) : new bytes(0); return abi.encodePacked(fid__Key, fid, hash__Key, hash__Length, hash); } // Encode a nested CastId, wrapped in key and length if non-default function encodeNested(uint64 field_number, CastId memory instance) internal pure returns (CastId__Encoded__Nested memory) { bytes memory nestedInstance = encode(instance); uint64 len = uint64(nestedInstance.length); bytes memory key = len > 0 ? ProtobufLib.encode_key(field_number, 2) : new bytes(0); bytes memory length = len > 0 ? ProtobufLib.encode_uint64(len) : new bytes(0); return CastId__Encoded__Nested(key, length, nestedInstance); } function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, CastId memory) { // Message instance CastId memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 2) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, CastId memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // CastId.fid function decode_1(uint64 pos, bytes memory buf, CastId memory instance) internal pure returns (bool, uint64) { bool success; uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.fid = v; return (true, pos); } // CastId.hash_ function decode_2(uint64 pos, bytes memory buf, CastId memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.hash_ = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.hash_[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } } struct ReactionBody { ReactionType type_; CastId target_cast_id; string target_url; } library ReactionBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, ReactionBody memory) { // Message instance ReactionBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 3) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, ReactionBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // ReactionBody.type_ function decode_1(uint64 pos, bytes memory buf, ReactionBody memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 2) { return (false, pos); } instance.type_ = ReactionType(v); return (true, pos); } // ReactionBody.target_cast_id function decode_2(uint64 pos, bytes memory buf, ReactionBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } CastId memory nestedInstance; (success, pos, nestedInstance) = CastIdCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.target_cast_id = nestedInstance; return (true, pos); } // ReactionBody.target_url function decode_3(uint64 pos, bytes memory buf, ReactionBody memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.target_url = v; return (true, pos); } } struct VerificationAddEthAddressBody { bytes address_; bytes eth_signature; bytes block_hash; uint32 verification_type; uint32 chain_id; } library VerificationAddEthAddressBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, VerificationAddEthAddressBody memory) { // Message instance VerificationAddEthAddressBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 5) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 4) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 5) { return wire_type == ProtobufLib.WireType.Varint; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, VerificationAddEthAddressBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 4) { bool success; (success, pos) = decode_4(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 5) { bool success; (success, pos) = decode_5(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // VerificationAddEthAddressBody.address_ function decode_1(uint64 pos, bytes memory buf, VerificationAddEthAddressBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.address_ = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.address_[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // VerificationAddEthAddressBody.eth_signature function decode_2(uint64 pos, bytes memory buf, VerificationAddEthAddressBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.eth_signature = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.eth_signature[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // VerificationAddEthAddressBody.block_hash function decode_3(uint64 pos, bytes memory buf, VerificationAddEthAddressBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.block_hash = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.block_hash[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // VerificationAddEthAddressBody.verification_type function decode_4(uint64 pos, bytes memory buf, VerificationAddEthAddressBody memory instance) internal pure returns (bool, uint64) { bool success; uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.verification_type = v; return (true, pos); } // VerificationAddEthAddressBody.chain_id function decode_5(uint64 pos, bytes memory buf, VerificationAddEthAddressBody memory instance) internal pure returns (bool, uint64) { bool success; uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.chain_id = v; return (true, pos); } } struct VerificationRemoveBody { bytes address_; } library VerificationRemoveBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, VerificationRemoveBody memory) { // Message instance VerificationRemoveBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 1) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, VerificationRemoveBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // VerificationRemoveBody.address_ function decode_1(uint64 pos, bytes memory buf, VerificationRemoveBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.address_ = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.address_[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } } struct LinkBody { string type_; uint32 displayTimestamp; uint64 target_fid; } library LinkBodyCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, LinkBody memory) { // Message instance LinkBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 3) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.Varint; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, LinkBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // LinkBody.type_ function decode_1(uint64 pos, bytes memory buf, LinkBody memory instance) internal pure returns (bool, uint64) { bool success; string memory v; (success, pos, v) = ProtobufLib.decode_string(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (bytes(v).length == 0) { return (false, pos); } instance.type_ = v; return (true, pos); } // LinkBody.displayTimestamp function decode_2(uint64 pos, bytes memory buf, LinkBody memory instance) internal pure returns (bool, uint64) { bool success; uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.displayTimestamp = v; return (true, pos); } // LinkBody.target_fid function decode_3(uint64 pos, bytes memory buf, LinkBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.target_fid = v; return (true, pos); } } struct FrameActionBody { bytes url; uint32 button_index; CastId cast_id; } library FrameActionBodyCodec { // Holds encoded version of nested message struct FrameActionBody__Encoded__Nested { bytes key; bytes length; bytes nestedInstance; } function encode(FrameActionBody memory instance) internal pure returns (bytes memory) { bytes memory url__Key = instance.url.length > 0 ? ProtobufLib.encode_key(1, uint64(ProtobufLib.WireType.LengthDelimited)) : new bytes(0); bytes memory url__Length = instance.url.length > 0 ? ProtobufLib.encode_uint64(uint64(instance.url.length)) : new bytes(0); bytes memory url = instance.url.length > 0 ? bytes(instance.url) : new bytes(0); bytes memory button_index__Key = uint64(instance.button_index) != 0 ? ProtobufLib.encode_key(2, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); bytes memory button_index = uint64(instance.button_index) != 0 ? ProtobufLib.encode_uint32(instance.button_index) : new bytes(0); CastIdCodec.CastId__Encoded__Nested memory cast_id = CastIdCodec.encodeNested(3, instance.cast_id); bytes memory cast_id__Encoded = abi.encodePacked(cast_id.key, cast_id.length, cast_id.nestedInstance); return abi.encodePacked(url__Key, url__Length, url, button_index__Key, button_index, cast_id__Encoded); } // Encode a nested FrameActionBody, wrapped in key and length if non-default function encodeNested(uint64 field_number, FrameActionBody memory instance) internal pure returns (FrameActionBody__Encoded__Nested memory) { bytes memory nestedInstance = encode(instance); uint64 len = uint64(nestedInstance.length); bytes memory key = len > 0 ? ProtobufLib.encode_key(field_number, 2) : new bytes(0); bytes memory length = len > 0 ? ProtobufLib.encode_uint64(len) : new bytes(0); return FrameActionBody__Encoded__Nested(key, length, nestedInstance); } function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, FrameActionBody memory) { // Message instance FrameActionBody memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 3) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.LengthDelimited; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, FrameActionBody memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // FrameActionBody.url function decode_1(uint64 pos, bytes memory buf, FrameActionBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.url = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.url[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // FrameActionBody.button_index function decode_2(uint64 pos, bytes memory buf, FrameActionBody memory instance) internal pure returns (bool, uint64) { bool success; uint32 v; (success, pos, v) = ProtobufLib.decode_uint32(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.button_index = v; return (true, pos); } // FrameActionBody.cast_id function decode_3(uint64 pos, bytes memory buf, FrameActionBody memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_embedded_message(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } CastId memory nestedInstance; (success, pos, nestedInstance) = CastIdCodec.decode(pos, buf, len); if (!success) { return (false, pos); } instance.cast_id = nestedInstance; return (true, pos); } } enum UserNameType { USERNAME_TYPE_NONE, USERNAME_TYPE_FNAME, USERNAME_TYPE_ENS_L1 } struct UserNameProof { uint64 timestamp; bytes name; bytes owner; bytes signature; uint64 fid; UserNameType type_; } library UserNameProofCodec { function decode(uint64 initial_pos, bytes memory buf, uint64 len) internal pure returns (bool, uint64, UserNameProof memory) { // Message instance UserNameProof memory instance; // Previous field number uint64 previous_field_number = 0; // Current position in the buffer uint64 pos = initial_pos; // Sanity checks if (pos + len < pos) { return (false, pos, instance); } while (pos - initial_pos < len) { // Decode the key (field number and wire type) bool success; uint64 field_number; ProtobufLib.WireType wire_type; (success, pos, field_number, wire_type) = ProtobufLib.decode_key(pos, buf); if (!success) { return (false, pos, instance); } // Check that the field number is within bounds if (field_number > 6) { return (false, pos, instance); } // Check that the field number of monotonically increasing if (field_number <= previous_field_number) { return (false, pos, instance); } // Check that the wire type is correct success = check_key(field_number, wire_type); if (!success) { return (false, pos, instance); } // Actually decode the field (success, pos) = decode_field(pos, buf, len, field_number, instance); if (!success) { return (false, pos, instance); } previous_field_number = field_number; } // Decoding must have consumed len bytes if (pos != initial_pos + len) { return (false, pos, instance); } return (true, pos, instance); } function check_key(uint64 field_number, ProtobufLib.WireType wire_type) internal pure returns (bool) { if (field_number == 1) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 2) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 3) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 4) { return wire_type == ProtobufLib.WireType.LengthDelimited; } if (field_number == 5) { return wire_type == ProtobufLib.WireType.Varint; } if (field_number == 6) { return wire_type == ProtobufLib.WireType.Varint; } return false; } function decode_field( uint64 initial_pos, bytes memory buf, uint64, // len uint64 field_number, UserNameProof memory instance ) internal pure returns (bool, uint64) { uint64 pos = initial_pos; if (field_number == 1) { bool success; (success, pos) = decode_1(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 2) { bool success; (success, pos) = decode_2(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 3) { bool success; (success, pos) = decode_3(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 4) { bool success; (success, pos) = decode_4(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 5) { bool success; (success, pos) = decode_5(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } if (field_number == 6) { bool success; (success, pos) = decode_6(pos, buf, instance); if (!success) { return (false, pos); } return (true, pos); } return (false, pos); } // UserNameProof.timestamp function decode_1(uint64 pos, bytes memory buf, UserNameProof memory instance) internal pure returns (bool, uint64) { bool success; uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.timestamp = v; return (true, pos); } // UserNameProof.name function decode_2(uint64 pos, bytes memory buf, UserNameProof memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.name = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.name[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // UserNameProof.owner function decode_3(uint64 pos, bytes memory buf, UserNameProof memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.owner = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.owner[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // UserNameProof.signature function decode_4(uint64 pos, bytes memory buf, UserNameProof memory instance) internal pure returns (bool, uint64) { bool success; uint64 len; (success, pos, len) = ProtobufLib.decode_bytes(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (len == 0) { return (false, pos); } instance.signature = new bytes(len); for (uint64 i = 0; i < len; i++) { instance.signature[i] = buf[pos + i]; } pos = pos + len; return (true, pos); } // UserNameProof.fid function decode_5(uint64 pos, bytes memory buf, UserNameProof memory instance) internal pure returns (bool, uint64) { bool success; uint64 v; (success, pos, v) = ProtobufLib.decode_uint64(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } instance.fid = v; return (true, pos); } // UserNameProof.type_ function decode_6(uint64 pos, bytes memory buf, UserNameProof memory instance) internal pure returns (bool, uint64) { bool success; int32 v; (success, pos, v) = ProtobufLib.decode_enum(pos, buf); if (!success) { return (false, pos); } // Default value must be omitted if (v == 0) { return (false, pos); } // Check that value is within enum range if (v < 0 || v > 2) { return (false, pos); } instance.type_ = UserNameType(v); return (true, pos); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.9; library Blake3 { uint256 constant BLOCK_LEN = 64; uint32 constant OUT_LEN = 32; uint32 constant CHUNK_LEN = 1024; // Flag constants uint32 constant CHUNK_START = 1 << 0; uint32 constant CHUNK_END = 1 << 1; uint32 constant PARENT = 1 << 2; uint32 constant ROOT = 1 << 3; uint32 constant KEYED_HASH = 1 << 4; uint32 constant DERIVE_KEY_CONTEXT = 1 << 5; uint32 constant DERIVE_KEY_MATERIAL = 1 << 6; // Product of a ChunkState before deriving chain value struct Output { uint32[8] input_chaining_value; uint32[16] block_words; uint64 counter; uint256 block_len; uint32 flags; } struct ChunkState { uint32[8] chaining_value; uint64 chunk_counter; // Has a max size of BLOCK_LEN bytes block_bytes; uint256 block_len; uint256 blocks_compressed; uint32 flags; } // An incremental hasher that can accept any number of writes. struct Hasher { ChunkState chunk_state; uint32[8] key_words; uint32[8][54] cv_stack; // Space for 54 subtree chaining values: uint8 cv_stack_len; // 2^54 * CHUNK_LEN = 2^64 uint32 flags; } // INTERNAL FUNCTIONS // This should remain constant but solidity doesn't support declaring it // uint8[16] MSG_PERMUTATION = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; // uint32[8] IV = [ // 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 // ]; function _MSG_PERMUTATION() internal pure returns (uint8[16] memory) { return [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; } function _IV() internal pure returns (uint32[8] memory) { return [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]; } // Mixing function G function _g( uint32[16] memory state, uint32 a, uint32 b, uint32 c, uint32 d, uint32 mx, uint32 my ) internal pure { unchecked { state[a] = state[a] + state[b] + mx; state[d] = _rotr(state[d] ^ state[a], 16); state[c] = state[c] + state[d]; state[b] = _rotr(state[b] ^ state[c], 12); state[a] = state[a] + state[b] + my; state[d] = _rotr(state[d] ^ state[a], 8); state[c] = state[c] + state[d]; state[b] = _rotr(state[b] ^ state[c], 7); } } function _round(uint32[16] memory state, uint32[16] memory m) internal pure { // Mix the columns. _g(state, 0, 4, 8, 12, m[0], m[1]); _g(state, 1, 5, 9, 13, m[2], m[3]); _g(state, 2, 6, 10, 14, m[4], m[5]); _g(state, 3, 7, 11, 15, m[6], m[7]); // Mix the diagonals. _g(state, 0, 5, 10, 15, m[8], m[9]); _g(state, 1, 6, 11, 12, m[10], m[11]); _g(state, 2, 7, 8, 13, m[12], m[13]); _g(state, 3, 4, 9, 14, m[14], m[15]); } function _permute(uint32[16] memory m) internal pure { uint8[16] memory MSG_PERMUTATION = _MSG_PERMUTATION(); uint32[16] memory permuted; for (uint256 i = 0; i < 16; ++i) { permuted[i] = m[MSG_PERMUTATION[i]]; } for (uint256 i = 0; i < 16; ++i) { m[i] = permuted[i]; } } function _compress( uint32[8] memory chaining_value, uint32[16] memory block_words_ref, uint64 counter, uint256 block_len, uint32 flags ) internal pure returns (uint32[16] memory) { uint32[8] memory IV = _IV(); uint32[16] memory block_words; for (uint256 i = 0; i < 16; ++i) { block_words[i] = block_words_ref[i]; } uint32[16] memory state = [ chaining_value[0], chaining_value[1], chaining_value[2], chaining_value[3], chaining_value[4], chaining_value[5], chaining_value[6], chaining_value[7], IV[0], IV[1], IV[2], IV[3], uint32(counter), uint32(counter >> 32), /////////////////////////////// uint32(block_len), flags ]; _round(state, block_words); // round 1 _permute(block_words); _round(state, block_words); // round 2 _permute(block_words); _round(state, block_words); // round 3 _permute(block_words); _round(state, block_words); // round 4 _permute(block_words); _round(state, block_words); // round 5 _permute(block_words); _round(state, block_words); // round 6 _permute(block_words); _round(state, block_words); // round 7 for (uint256 i = 0; i < 8; ++i) { state[i] ^= state[i + 8]; state[i + 8] ^= chaining_value[i]; } return state; } function _rotr(uint32 x, uint8 n) internal pure returns (uint32) { bytes4 b = bytes4(x); return uint32((b >> n) | (b << (32 - n))); } function _chaining_value(Output memory o) internal pure returns (uint32[8] memory) { uint32[16] memory compression_output = _compress( o.input_chaining_value, o.block_words, o.counter, o.block_len, o.flags ); return _first_8_words(compression_output); } function _root_output_bytes( Output memory self, bytes memory out_slice ) internal pure { //uint32 output_block_counter = 0; // Take 64-byte chunks at a time from out_slice //for (uint32 i = 0; i < out_slice.length; i += 2 * OUT_LEN) { uint32[16] memory words = _compress( self.input_chaining_value, self.block_words, 0, //output_block_counter, self.block_len, self.flags | ROOT ); // Load compressed words into out_slice (4 bytes at a time) // The output length might not be a multiple of 4. //for (uint32 j = 0; j < words.length && out_slice.length > j*4; j++) { //for (uint32 j = 0; j < words.length; j++) { for (uint32 j = 0; j < 8; j++) { // Load word at j into out_slice as little endian _load_uint32_to_le_bytes(words[j], out_slice, j*4); } //output_block_counter += 1; //} } function _load_uint32_to_le_bytes( uint32 n, bytes memory buf, uint32 offset ) internal pure { for (uint256 i = 0; i < 4; ++i) { buf[offset+i] = bytes1(uint8(n / (2 ** (i*8)))); } } function _uint32_to_le_bytes(uint32 n) internal pure returns (bytes4) { bytes4 buf; for (uint256 i = 0; i < 4; ++i) { assembly { let cc := add(buf, 0x20) let buf_idx := add(cc, sub(3, i)) let n_idx := add(n, i) mstore8(buf_idx, n_idx) } } return buf; } function _le_bytes_get_uint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "le_bytes_get_uint32_outOfBounds"); uint32 tempUint; for (uint256 i = 0; i < 4; ++i) { //tempUint += uint32(uint8(_bytes[i]) * (2 ** (8*i))); tempUint += uint32(bytes4(_bytes[3-i+_start]) >> (8 * i)); } /* assembly { // TODO why is this 0x4 in the bytes library??? //tempUint := mload(add(add(_bytes, 0x4), _start)) // Load 32 bytes from array (u256) tempUint := mload(add(add(_bytes, 0x20), _start)) // Keep just the first 4 bytes (u32) //tempUint := xor(tempUint, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000) tempUint := xor(tempUint, 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } */ return tempUint; } function _words_from_little_endian_bytes8( bytes memory data_bytes, uint32[8] memory words ) internal pure { require(data_bytes.length <= 4*8, "Data bytes is too long to convert to 8 4-byte words"); for (uint256 i = 0; i < data_bytes.length/4; ++i) { words[i] = _le_bytes_get_uint32(data_bytes, i*4); } } function _words_from_little_endian_bytes( bytes memory data_bytes, uint32[16] memory words ) internal pure { require(data_bytes.length <= 64 && data_bytes.length%4 == 0, "Data bytes is too long to convert to 16 4-byte words"); for (uint256 i = 0; i < data_bytes.length/4; ++i) { words[i] = _le_bytes_get_uint32(data_bytes, i*4); } } // TODO I wish this didn't require a copy to convert array sizes function _first_8_words(uint32[16] memory words) internal pure returns (uint32[8] memory) { // TODO there must be a way to do this without copying // How to take a slice of a memory array? uint32[8] memory first_8; for (uint256 i = 0; i < 8; ++i) { first_8[i] = words[i]; } return first_8; } // // Chunk state functions // function _new_chunkstate( uint32[8] memory key_words, uint64 chunk_counter, uint32 flags ) internal pure returns (ChunkState memory) { bytes memory block_bytes = new bytes(BLOCK_LEN); return ChunkState({ chaining_value: key_words, chunk_counter: chunk_counter, block_bytes: block_bytes, block_len: 0, blocks_compressed: 0, flags: flags }); } function _len(ChunkState memory chunk) internal pure returns (uint256) { return BLOCK_LEN * chunk.blocks_compressed + chunk.block_len; } function _start_flag(ChunkState memory chunk) internal pure returns (uint32) { if (chunk.blocks_compressed == 0) { return CHUNK_START; } else { return 0; } } // Returns a new input offset function _update_chunkstate( ChunkState memory chunk, bytes memory input ) internal pure {//returns (uint32) { uint256 input_offset = 0; while (input_offset < input.length) { // If the block buffer is full, compress it and clear it. More // input is coming, so this compression is not CHUNK_END. if (chunk.block_len == BLOCK_LEN) { uint32[16] memory block_words; _words_from_little_endian_bytes(chunk.block_bytes, block_words); chunk.chaining_value = _first_8_words(_compress( chunk.chaining_value, block_words, chunk.chunk_counter, BLOCK_LEN, chunk.flags | _start_flag(chunk) )); chunk.blocks_compressed += 1; // TODO probably cheaper to zero-out byte array than to reallocate chunk.block_bytes = new bytes(BLOCK_LEN); chunk.block_len = 0; } // Take enough to fill a block [min(want, input.length)] uint256 want = BLOCK_LEN - chunk.block_len; uint256 take = _min(want, input.length - input_offset); // Copy bytes from input to chunk block //chunk.block_bytes[self.block_len as usize..][..take].copy_from_slice(&input[..take]); for (uint256 i = 0; i < take; ++i) { // TODO recheck this logic chunk.block_bytes[i+chunk.block_len] = input[input_offset+i]; } /* bytes memory block_ref = chunk.block_bytes; uint32 blen = chunk.block_len; assembly { let block_addr := add(add(block_ref, 0x20), blen) let input_addr := add(add(input.offset, 0x20), input_offset) memorycopy(block_addr, input_addr, take) } */ chunk.block_len += take; input_offset += take; } } function _min(uint256 x, uint256 y) internal pure returns (uint256) { if (x < y) { return x; } else { return y; } } function _output(ChunkState memory chunk) internal pure returns (Output memory) { uint32[16] memory block_words; _words_from_little_endian_bytes(chunk.block_bytes, block_words); return Output({ input_chaining_value: chunk.chaining_value, block_words: block_words, counter: chunk.chunk_counter, block_len: chunk.block_len, flags: chunk.flags | _start_flag(chunk) | CHUNK_END }); } // // Parent functions // function _parent_output( uint32[8] memory left_child_cv, uint32[8] memory right_child_cv, uint32[8] memory key_words, uint32 flags ) internal pure returns (Output memory) { uint32[16] memory block_words; for (uint256 i = 0; i < 8; ++i) { block_words[i] = left_child_cv[i]; } for (uint256 i = 8; i < 16; ++i) { block_words[i] = right_child_cv[i - 8]; } return Output({ input_chaining_value: key_words, block_words: block_words, counter: 0, // Always 0 for parent nodes. block_len: BLOCK_LEN, // Always BLOCK_LEN (64) for parent nodes. flags: PARENT | flags }); } function _parent_cv( uint32[8] memory left_child_cv, uint32[8] memory right_child_cv, uint32[8] memory key_words, uint32 flags ) internal pure returns (uint32[8] memory) { return _chaining_value(_parent_output(left_child_cv, right_child_cv, key_words, flags)); } // // Hasher functions // function _new_hasher_internal( uint32[8] memory key_words, uint32 flags ) internal pure returns (Hasher memory) { uint32[8][54] memory cv_stack; return Hasher({ chunk_state: _new_chunkstate(key_words, 0, flags), key_words: key_words, cv_stack: cv_stack, cv_stack_len: 0, flags: flags }); } /// Construct a new `Hasher` for the regular hash function. function new_hasher() internal pure returns (Hasher memory) { uint32[8] memory IV = _IV(); return _new_hasher_internal(IV, 0); } /// Construct a new `Hasher` for the keyed hash function. function new_keyed(bytes memory key) internal pure returns (Hasher memory) { uint32[8] memory key_words; bytes memory key_mem = key; _words_from_little_endian_bytes8(key_mem, key_words); return _new_hasher_internal(key_words, KEYED_HASH); } // Construct a new `Hasher` for the key derivation function. The context // string should be hardcoded, globally unique, and application-specific function new_derive_key(bytes memory context) internal pure returns (Hasher memory) { uint32[8] memory IV = _IV(); Hasher memory context_hasher = _new_hasher_internal(IV, DERIVE_KEY_CONTEXT); update_hasher(context_hasher, context); bytes memory context_key = new bytes(256); _finalize_internal(context_hasher, context_key); uint32[8] memory context_key_words; _words_from_little_endian_bytes8(context_key, context_key_words); return _new_hasher_internal(context_key_words, DERIVE_KEY_MATERIAL); } function _push_stack(Hasher memory self, uint32[8] memory cv) internal pure { self.cv_stack[self.cv_stack_len] = cv; self.cv_stack_len += 1; } function _pop_stack(Hasher memory self) internal pure returns (uint32[8] memory) { self.cv_stack_len -= 1; return self.cv_stack[self.cv_stack_len]; } function _add_chunk_chaining_value( Hasher memory self, uint32[8] memory new_cv, uint64 total_chunks ) internal pure { while (total_chunks & 1 == 0) { new_cv = _parent_cv(_pop_stack(self), new_cv, self.key_words, self.flags); total_chunks >>= 1; } _push_stack(self, new_cv); } function _slice( bytes memory data, uint256 start, uint256 end ) internal pure returns (bytes memory) { uint256 dataSliceLength = end - start; bytes memory dataSlice = new bytes(dataSliceLength); for (uint256 i = 0; i < dataSliceLength; ++i) { dataSlice[i] = data[start + i]; } return dataSlice; } // Add input to the hash state. This can be called any number of times. function update_hasher( Hasher memory self, bytes memory input ) internal pure returns (Hasher memory) { uint256 input_offset = 0; while (input_offset < input.length) { // If the current chunk is complete, finalize it and reset the // chunk state. More input is coming, so this chunk is not ROOT. if (_len(self.chunk_state) == CHUNK_LEN) { uint32[8] memory chunk_cv = _chaining_value(_output(self.chunk_state)); uint64 total_chunks = self.chunk_state.chunk_counter + 1; _add_chunk_chaining_value(self, chunk_cv, total_chunks); self.chunk_state = _new_chunkstate(self.key_words, total_chunks, self.flags); } // Compress input bytes into the current chunk state. uint256 want = CHUNK_LEN - _len(self.chunk_state); uint256 take = _min(want, uint32(input.length - input_offset)); // Update chunk state bytes memory input_slice = _slice(input, input_offset, take + input_offset); _update_chunkstate(self.chunk_state, input_slice); input_offset += take; } return self; } function finalize(Hasher memory self) internal pure returns (bytes memory) { bytes memory output = new bytes(32); _finalize_internal(self, output); return output; } function _finalize_internal( Hasher memory self, bytes memory out_slice ) internal pure { // Starting with the Output from the current chunk, compute all the // parent chaining values along the right edge of the tree, until we // have the root Output. Output memory output = _output(self.chunk_state); uint32 parent_nodes_remaining = self.cv_stack_len; while (parent_nodes_remaining > 0) { parent_nodes_remaining -= 1; output = _parent_output( self.cv_stack[parent_nodes_remaining], _chaining_value(output), self.key_words, self.flags ); } _root_output_bytes(output, out_slice); } function sliceBytes(bytes memory message, uint64 length) internal pure returns (bytes memory) { require(length <= message.length, "Length exceeds message length"); // Overwrite the length field of the bytes to crop the message assembly { mstore(message, length) } return message; } function hash( bytes memory message, uint32 length ) external pure returns (bytes memory) { Hasher memory hasher = new_hasher(); update_hasher(hasher, message); return sliceBytes(finalize(hasher), length); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.9; import "./Sha512.sol"; import "./Ed25519_pow.sol"; library Ed25519 { function verify( bytes32 k, bytes32 r, bytes32 s, bytes memory m ) external pure returns (bool) { unchecked { uint256 hh; // Step 1: compute SHA-512(R, A, M) { bytes memory rs = new bytes(k.length + r.length + m.length); for (uint256 i = 0; i < r.length; i++) { rs[i] = r[i]; } for (uint256 i = 0; i < k.length; i++) { rs[i + 32] = k[i]; } for (uint256 i = 0; i < m.length; i++) { rs[i + 64] = m[i]; } uint64[8] memory result = Sha512.hash(rs); uint256 h0 = uint256(result[0]) | uint256(result[1]) << 64 | uint256(result[2]) << 128 | uint256(result[3]) << 192; h0 = ((h0 & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) | ((h0 & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8); h0 = ((h0 & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) | ((h0 & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16); h0 = ((h0 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) | ((h0 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32); uint256 h1 = uint256(result[4]) | uint256(result[5]) << 64 | uint256(result[6]) << 128 | uint256(result[7]) << 192; h1 = ((h1 & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) | ((h1 & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8); h1 = ((h1 & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) | ((h1 & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16); h1 = ((h1 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) | ((h1 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32); hh = addmod( h0, mulmod( h1, 0xfffffff_ffffffff_ffffffff_fffffffe_c6ef5bf4_737dcf70_d6ec3174_8d98951d, 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed ), 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed ); } // Step 2: unpack k k = bytes32( ((uint256(k) & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) | ((uint256(k) & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8) ); k = bytes32( ((uint256(k) & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) | ((uint256(k) & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16) ); k = bytes32( ((uint256(k) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) | ((uint256(k) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32) ); k = bytes32( ((uint256(k) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) << 64) | ((uint256(k) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) >> 64) ); k = bytes32((uint256(k) << 128) | (uint256(k) >> 128)); uint256 ky = uint256(k) & 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff; uint256 kx; { uint256 ky2 = mulmod(ky, ky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 u = addmod( ky2, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffec, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 v = mulmod( ky2, 0x52036cee_2b6ffe73_8cc74079_7779e898_00700a4d_4141d8ab_75eb4dca_135978a3, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ) + 1; uint256 t = mulmod(u, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); (kx, ) = Ed25519_pow.pow22501(t); kx = mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); kx = mulmod( u, mulmod( mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), t, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ), 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); t = mulmod( mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); if (t != u) { if (t != 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - u) { return false; } kx = mulmod( kx, 0x2b832480_4fc1df0b_2b4d0099_3dfbd7a7_2f431806_ad2fe478_c4ee1b27_4a0ea0b0, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } } if ((kx & 1) != uint256(k) >> 255) { kx = 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - kx; } // Verify s s = bytes32( ((uint256(s) & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) | ((uint256(s) & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8) ); s = bytes32( ((uint256(s) & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) | ((uint256(s) & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16) ); s = bytes32( ((uint256(s) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) | ((uint256(s) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32) ); s = bytes32( ((uint256(s) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) << 64) | ((uint256(s) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) >> 64) ); s = bytes32((uint256(s) << 128) | (uint256(s) >> 128)); if (uint256(s) >= 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed) { return false; } uint256 vx; uint256 vu; uint256 vy; uint256 vv; // Step 3: compute multiples of k uint256[8][3][2] memory tables; { uint256 ks = ky + kx; uint256 kd = ky + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - kx; uint256 k2dt = mulmod( mulmod(kx, ky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 0x2406d9dc_56dffce7_198e80f2_eef3d130_00e0149a_8283b156_ebd69b94_26b2f159, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 kky = ky; uint256 kkx = kx; uint256 kku = 1; uint256 kkv = 1; { uint256 xx = mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy = mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz = mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xx2 = mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy2 = mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xxyy = mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz2 = mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); kkx = xxyy + xxyy; kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; kky = xx2 + yy2; kkv = addmod( zz2 + zz2, 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } { uint256 xx = mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy = mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz = mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xx2 = mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy2 = mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xxyy = mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz2 = mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); kkx = xxyy + xxyy; kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; kky = xx2 + yy2; kkv = addmod( zz2 + zz2, 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } { uint256 xx = mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy = mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz = mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xx2 = mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy2 = mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xxyy = mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz2 = mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); kkx = xxyy + xxyy; kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; kky = xx2 + yy2; kkv = addmod( zz2 + zz2, 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } uint256 cprod = 1; uint256[8][3][2] memory tables_ = tables; for (uint256 i = 0; ; i++) { uint256 cs; uint256 cd; uint256 ct; uint256 c2z; { uint256 cx = mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 cy = mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 cz = mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); ct = mulmod( kkx, kky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); cs = cy + cx; cd = cy - cx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; c2z = cz + cz; } tables_[1][0][i] = cs; tables_[1][1][i] = cd; tables_[1][2][i] = mulmod( ct, 0x2406d9dc_56dffce7_198e80f2_eef3d130_00e0149a_8283b156_ebd69b94_26b2f159, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); tables_[0][0][i] = c2z; tables_[0][1][i] = cprod; cprod = mulmod( cprod, c2z, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); if (i == 7) { break; } uint256 ab = mulmod(cs, ks, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 aa = mulmod(cd, kd, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 ac = mulmod(ct, k2dt, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); kkx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; kku = addmod(c2z, ac, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); kky = ab + aa; kkv = addmod( c2z, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - ac, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } uint256 t; (cprod, t) = Ed25519_pow.pow22501(cprod); cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); cprod = mulmod(cprod, t, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); for (uint256 i = 7; ; i--) { uint256 cinv = mulmod( cprod, tables_[0][1][i], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); tables_[1][0][i] = mulmod( tables_[1][0][i], cinv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); tables_[1][1][i] = mulmod( tables_[1][1][i], cinv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); tables_[1][2][i] = mulmod( tables_[1][2][i], cinv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); if (i == 0) { break; } cprod = mulmod( cprod, tables_[0][0][i], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } tables_[0] = [ [ 0x43e7ce9d_19ea5d32_9385a44c_321ea161_67c996e3_7dc6070c_97de49e3_7ac61db9, 0x40cff344_25d8ec30_a3bb74ba_58cd5854_fa1e3818_6ad0d31e_bc8ae251_ceb2c97e, 0x459bd270_46e8dd45_aea7008d_b87a5a8f_79067792_53d64523_58951859_9fdfbf4b, 0x69fdd1e2_8c23cc38_94d0c8ff_90e76f6d_5b6e4c2e_620136d0_4dd83c4a_51581ab9, 0x54dceb34_13ce5cfa_11196dfc_960b6eda_f4b380c6_d4d23784_19cc0279_ba49c5f3, 0x4e24184d_d71a3d77_eef3729f_7f8cf7c1_7224cf40_aa7b9548_b9942f3c_5084ceed, 0x5a0e5aab_20262674_ae117576_1cbf5e88_9b52a55f_d7ac5027_c228cebd_c8d2360a, 0x26239334_073e9b38_c6285955_6d451c3d_cc8d30e8_4b361174_f488eadd_e2cf17d9 ], [ 0x227e97c9_4c7c0933_d2e0c21a_3447c504_fe9ccf82_e8a05f59_ce881c82_eba0489f, 0x226a3e0e_cc4afec6_fd0d2884_13014a9d_bddecf06_c1a2f0bb_702ba77c_613d8209, 0x34d7efc8_51d45c5e_71efeb0f_235b7946_91de6228_877569b3_a8d52bf0_58b8a4a0, 0x3c1f5fb3_ca7166fc_e1471c9b_752b6d28_c56301ad_7b65e845_1b2c8c55_26726e12, 0x6102416c_f02f02ff_5be75275_f55f28db_89b2a9d2_456b860c_e22fc0e5_031f7cc5, 0x40adf677_f1bfdae0_57f0fd17_9c126179_18ddaa28_91a6530f_b1a4294f_a8665490, 0x61936f3c_41560904_6187b8ba_a978cbc9_b4789336_3ae5a3cc_7d909f36_35ae7f48, 0x562a9662_b6ec47f9_e979d473_c02b51e4_42336823_8c58ddb5_2f0e5c6a_180e6410 ], [ 0x3788bdb4_4f8632d4_2d0dbee5_eea1acc6_136cf411_e655624f_55e48902_c3bd5534, 0x6190cf2c_2a7b5ad7_69d594a8_2844f23b_4167fa7c_8ac30e51_aa6cfbeb_dcd4b945, 0x65f77870_96be9204_123a71f3_ac88a87b_e1513217_737d6a1e_2f3a13a4_3d7e3a9a, 0x23af32d_bfa67975_536479a7_a7ce74a0_2142147f_ac048018_7f1f1334_9cda1f2d, 0x64fc44b7_fc6841bd_db0ced8b_8b0fe675_9137ef87_ee966512_15fc1dbc_d25c64dc, 0x1434aa37_48b701d5_b69df3d7_d340c1fe_3f6b9c1e_fc617484_caadb47e_382f4475, 0x457a6da8_c962ef35_f2b21742_3e5844e9_d2353452_7e8ea429_0d24e3dd_f21720c6, 0x63b9540c_eb60ccb5_1e4d989d_956e053c_f2511837_efb79089_d2ff4028_4202c53d ] ]; } // Step 4: compute s*G - h*A { uint256 ss = uint256(s) << 3; uint256 hhh = hh + 0x80000000_00000000_00000000_00000000_a6f7cef5_17bce6b2_c09318d2_e7ae9f60; uint256 vvx = 0; uint256 vvu = 1; uint256 vvy = 1; uint256 vvv = 1; for (uint256 i = 252; ; i--) { uint256 bit = 8 << i; if ((ss & bit) != 0) { uint256 ws; uint256 wd; uint256 wz; uint256 wt; { uint256 wx = mulmod( vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 wy = mulmod( vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); ws = wy + wx; wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; wz = mulmod( vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); wt = mulmod( vvx, vvy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } uint256 j = (ss >> i) & 7; ss &= ~(7 << i); uint256[8][3][2] memory tables_ = tables; uint256 aa = mulmod( wd, tables_[0][1][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 ab = mulmod( ws, tables_[0][0][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 ac = mulmod( wt, tables_[0][2][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; vvu = wz + ac; vvy = ab + aa; vvv = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; } if ((hhh & bit) != 0) { uint256 ws; uint256 wd; uint256 wz; uint256 wt; { uint256 wx = mulmod( vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 wy = mulmod( vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); ws = wy + wx; wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; wz = mulmod( vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); wt = mulmod( vvx, vvy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } uint256 j = (hhh >> i) & 7; hhh &= ~(7 << i); uint256[8][3][2] memory tables_ = tables; uint256 aa = mulmod( wd, tables_[1][0][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 ab = mulmod( ws, tables_[1][1][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 ac = mulmod( wt, tables_[1][2][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; vvu = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; vvy = ab + aa; vvv = wz + ac; } if (i == 0) { uint256 ws; uint256 wd; uint256 wz; uint256 wt; { uint256 wx = mulmod( vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 wy = mulmod( vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); ws = wy + wx; wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; wz = mulmod( vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); wt = mulmod( vvx, vvy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } uint256 j = hhh & 7; uint256[8][3][2] memory tables_ = tables; uint256 aa = mulmod( wd, tables_[1][0][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 ab = mulmod( ws, tables_[1][1][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 ac = mulmod( wt, tables_[1][2][j], 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; vvu = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; vvy = ab + aa; vvv = wz + ac; break; } { uint256 xx = mulmod(vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy = mulmod(vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz = mulmod(vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xx2 = mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 yy2 = mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 xxyy = mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 zz2 = mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vvx = xxyy + xxyy; vvu = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; vvy = xx2 + yy2; vvv = addmod( zz2 + zz2, 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); } } vx = vvx; vu = vvu; vy = vvy; vv = vvv; } // Step 5: compare the points (uint256 vi, uint256 vj) = Ed25519_pow.pow22501(mulmod(vu, vv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed)); vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vi = mulmod(vi, vj, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); vx = mulmod( vx, mulmod(vi, vv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); vy = mulmod( vy, mulmod(vi, vu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); bytes32 vr = bytes32(vy | (vx << 255)); vr = bytes32( ((uint256(vr) & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) | ((uint256(vr) & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8) ); vr = bytes32( ((uint256(vr) & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) | ((uint256(vr) & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16) ); vr = bytes32( ((uint256(vr) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) | ((uint256(vr) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32) ); vr = bytes32( ((uint256(vr) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) << 64) | ((uint256(vr) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) >> 64) ); vr = bytes32((uint256(vr) << 128) | (uint256(vr) >> 128)); return vr == r; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; interface IMetadataValidator { /** * @notice Validate metadata associated with a key. * * @param userFid The fid associated with the key. * @param key Bytes of the key. * @param metadata Metadata about the key. * * @return bool Whether the provided key and metadata are valid. */ function validate(uint256 userFid, bytes memory key, bytes memory metadata) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; /** * @dev Minimal interface for IdRegistry, used by the KeyRegistry. */ interface IdRegistryLike { /*////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ /** * @notice Maps each address to an fid, or zero if it does not own an fid. */ function idOf(address fidOwner) external view returns (uint256); /*////////////////////////////////////////////////////////////// VIEWS //////////////////////////////////////////////////////////////*/ /** * @notice Verify that a signature was produced by the custody address that owns an fid. * * @param custodyAddress The address to check the signature of. * @param fid The fid to check the signature of. * @param digest The digest that was signed. * @param sig The signature to check. * * @return isValid Whether provided signature is valid. */ function verifyFidSignature( address custodyAddress, uint256 fid, bytes32 digest, bytes calldata sig ) external view returns (bool isValid); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.4 <0.9.0; library ProtobufLib { /// @notice Protobuf wire types. enum WireType { Varint, Bits64, LengthDelimited, StartGroup, EndGroup, Bits32, WIRE_TYPE_MAX } /// @dev Maximum number of bytes for a varint. /// @dev 64 bits, in groups of base-128 (7 bits). uint64 internal constant MAX_VARINT_BYTES = 10; //////////////////////////////////// // Decoding //////////////////////////////////// /// @notice Decode key. /// @dev https://developers.google.com/protocol-buffers/docs/encoding#structure /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Field number /// @return Wire type function decode_key(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64, WireType ) { // The key is a varint with encoding // (field_number << 3) | wire_type (bool success, uint64 pos, uint64 key) = decode_varint(p, buf); if (!success) { return (false, pos, 0, WireType.WIRE_TYPE_MAX); } uint64 field_number = key >> 3; uint64 wire_type_val = key & 0x07; // Check that wire type is bounded if (wire_type_val >= uint64(WireType.WIRE_TYPE_MAX)) { return (false, pos, 0, WireType.WIRE_TYPE_MAX); } WireType wire_type = WireType(wire_type_val); // Start and end group types are deprecated, so forbid them if (wire_type == WireType.StartGroup || wire_type == WireType.EndGroup) { return (false, pos, 0, WireType.WIRE_TYPE_MAX); } return (true, pos, field_number, wire_type); } /// @notice Decode varint. /// @dev https://developers.google.com/protocol-buffers/docs/encoding#varints /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_varint(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { uint64 val; uint64 i; for (i = 0; i < MAX_VARINT_BYTES; i++) { // Check that index is within bounds if (i + p >= buf.length) { return (false, p, 0); } // Get byte at offset uint8 b = uint8(buf[p + i]); // Highest bit is used to indicate if there are more bytes to come // Mask to get 7-bit value: 0111 1111 uint8 v = b & 0x7F; // Groups of 7 bits are ordered least significant first val |= uint64(v) << uint64(i * 7); // Mask to get keep going bit: 1000 0000 if (b & 0x80 == 0) { // [STRICT] // Check for trailing zeroes if more than one byte is used // (the value 0 still uses one byte) if (i > 0 && v == 0) { return (false, p, 0); } break; } } // Check that at most MAX_VARINT_BYTES are used if (i >= MAX_VARINT_BYTES) { return (false, p, 0); } // [STRICT] // If all 10 bytes are used, the last byte (most significant 7 bits) // must be at most 0000 0001, since 7*9 = 63 if (i == MAX_VARINT_BYTES - 1) { if (uint8(buf[p + i]) > 1) { return (false, p, 0); } } return (true, p + i + 1, val); } /// @notice Decode varint int32. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_int32(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int32 ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } // [STRICT] // Highest 4 bytes must be 0 if positive if (val >> 63 == 0) { if (val & 0xFFFFFFFF00000000 != 0) { return (false, pos, 0); } } return (true, pos, int32(uint32(val))); } /// @notice Decode varint int64. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_int64(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int64 ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } return (true, pos, int64(val)); } /// @notice Decode varint uint32. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_uint32(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint32 ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } // [STRICT] // Highest 4 bytes must be 0 if (val & 0xFFFFFFFF00000000 != 0) { return (false, pos, 0); } return (true, pos, uint32(val)); } /// @notice Decode varint uint64. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_uint64(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } return (true, pos, val); } /// @notice Decode varint sint32. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_sint32(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int32 ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } // [STRICT] // Highest 4 bytes must be 0 if (val & 0xFFFFFFFF00000000 != 0) { return (false, pos, 0); } // https://stackoverflow.com/questions/2210923/zig-zag-decoding/2211086#2211086 uint64 zigzag_val; unchecked { zigzag_val = (val >> 1) - (~(val & 1) + 1); } return (true, pos, int32(uint32(zigzag_val))); } /// @notice Decode varint sint64. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_sint64(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int64 ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } // https://stackoverflow.com/questions/2210923/zig-zag-decoding/2211086#2211086 uint64 zigzag_val; unchecked { zigzag_val = (val >> 1) - (~(val & 1) + 1); } return (true, pos, int64(zigzag_val)); } /// @notice Decode Boolean. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded bool function decode_bool(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, bool ) { (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); if (!success) { return (false, pos, false); } // [STRICT] // Value must be 0 or 1 if (val > 1) { return (false, pos, false); } if (val == 0) { return (true, pos, false); } return (true, pos, true); } /// @notice Decode enumeration. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded enum as raw int function decode_enum(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int32 ) { return decode_int32(p, buf); } /// @notice Decode fixed 64-bit int. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_bits64(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { uint64 val; // Check that index is within bounds if (8 + p > buf.length) { return (false, p, 0); } for (uint64 i = 0; i < 8; i++) { uint8 b = uint8(buf[p + i]); // Little endian val |= uint64(b) << uint64(i * 8); } return (true, p + 8, val); } /// @notice Decode fixed uint64. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_fixed64(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { (bool success, uint64 pos, uint64 val) = decode_bits64(p, buf); if (!success) { return (false, pos, 0); } return (true, pos, val); } /// @notice Decode fixed int64. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_sfixed64(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int64 ) { (bool success, uint64 pos, uint64 val) = decode_bits64(p, buf); if (!success) { return (false, pos, 0); } return (true, pos, int64(val)); } /// @notice Decode fixed 32-bit int. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_bits32(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint32 ) { uint32 val; // Check that index is within bounds if (4 + p > buf.length) { return (false, p, 0); } for (uint64 i = 0; i < 4; i++) { uint8 b = uint8(buf[p + i]); // Little endian val |= uint32(b) << uint32(i * 8); } return (true, p + 4, val); } /// @notice Decode fixed uint32. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_fixed32(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint32 ) { (bool success, uint64 pos, uint32 val) = decode_bits32(p, buf); if (!success) { return (false, pos, 0); } return (true, pos, val); } /// @notice Decode fixed int32. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Decoded int function decode_sfixed32(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, int32 ) { (bool success, uint64 pos, uint32 val) = decode_bits32(p, buf); if (!success) { return (false, pos, 0); } return (true, pos, int32(val)); } /// @notice Decode length-delimited field. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position (after size) /// @return Size in bytes function decode_length_delimited(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { // Length-delimited fields begin with a varint of the number of bytes that follow (bool success, uint64 pos, uint64 size) = decode_varint(p, buf); if (!success) { return (false, pos, 0); } // Check for overflow unchecked { if (pos + size < pos) { return (false, pos, 0); } } // Check that index is within bounds if (size + pos > buf.length) { return (false, pos, 0); } return (true, pos, size); } /// @notice Decode string. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position /// @return Size in bytes function decode_string(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, string memory ) { (bool success, uint64 pos, uint64 size) = decode_length_delimited(p, buf); if (!success) { return (false, pos, ""); } bytes memory field = new bytes(size); for (uint64 i = 0; i < size; i++) { field[i] = buf[pos + i]; } return (true, pos + size, string(field)); } /// @notice Decode bytes array. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position (after size) /// @return Size in bytes function decode_bytes(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { return decode_length_delimited(p, buf); } /// @notice Decode embedded message. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position (after size) /// @return Size in bytes function decode_embedded_message(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { return decode_length_delimited(p, buf); } /// @notice Decode packed repeated field. /// @param p Position /// @param buf Buffer /// @return Success /// @return New position (after size) /// @return Size in bytes function decode_packed_repeated(uint64 p, bytes memory buf) internal pure returns ( bool, uint64, uint64 ) { return decode_length_delimited(p, buf); } //////////////////////////////////// // Encoding //////////////////////////////////// /// @notice Encode key. /// @dev https://developers.google.com/protocol-buffers/docs/encoding#structure /// @param field_number Field number /// @param wire_type Wire type /// @return Marshaled bytes function encode_key(uint64 field_number, uint64 wire_type) internal pure returns (bytes memory) { uint64 key = (field_number << 3) | wire_type; bytes memory buf = encode_varint(key); return buf; } /// @notice Encode varint. /// @dev https://developers.google.com/protocol-buffers/docs/encoding#varints /// @param n Number /// @return Marshaled bytes function encode_varint(uint64 n) internal pure returns (bytes memory) { // Count the number of groups of 7 bits // We need this pre-processing step since Solidity doesn't allow dynamic memory resizing uint64 tmp = n; uint64 num_bytes = 1; while (tmp > 0x7F) { tmp = tmp >> 7; num_bytes += 1; } bytes memory buf = new bytes(num_bytes); tmp = n; for (uint64 i = 0; i < num_bytes; i++) { // Set the first bit in the byte for each group of 7 bits buf[i] = bytes1(0x80 | uint8(tmp & 0x7F)); tmp = tmp >> 7; } // Unset the first bit of the last byte buf[num_bytes - 1] &= 0x7F; return buf; } /// @notice Encode varint int32. /// @param n Number /// @return Marshaled bytes function encode_int32(int32 n) internal pure returns (bytes memory) { return encode_varint(uint64(int64(n))); } /// @notice Decode varint int64. /// @param n Number /// @return Marshaled bytes function encode_int64(int64 n) internal pure returns (bytes memory) { return encode_varint(uint64(n)); } /// @notice Encode varint uint32. /// @param n Number /// @return Marshaled bytes function encode_uint32(uint32 n) internal pure returns (bytes memory) { return encode_varint(n); } /// @notice Encode varint uint64. /// @param n Number /// @return Marshaled bytes function encode_uint64(uint64 n) internal pure returns (bytes memory) { return encode_varint(n); } /// @notice Encode varint sint32. /// @param n Number /// @return Marshaled bytes function encode_sint32(int32 n) internal pure returns (bytes memory) { // https://developers.google.com/protocol-buffers/docs/encoding#signed_integers uint32 mask = 0; if (n < 0) { unchecked { mask -= 1; } } uint32 zigzag_val = (uint32(n) << 1) ^ mask; return encode_varint(zigzag_val); } /// @notice Encode varint sint64. /// @param n Number /// @return Marshaled bytes function encode_sint64(int64 n) internal pure returns (bytes memory) { // https://developers.google.com/protocol-buffers/docs/encoding#signed_integers uint64 mask = 0; if (n < 0) { unchecked { mask -= 1; } } uint64 zigzag_val = (uint64(n) << 1) ^ mask; return encode_varint(zigzag_val); } /// @notice Encode Boolean. /// @param b Boolean /// @return Marshaled bytes function encode_bool(bool b) internal pure returns (bytes memory) { uint64 n = b ? 1 : 0; return encode_varint(n); } /// @notice Encode enumeration. /// @param n Number /// @return Marshaled bytes function encode_enum(int32 n) internal pure returns (bytes memory) { return encode_int32(n); } /// @notice Encode fixed 64-bit int. /// @param n Number /// @return Marshaled bytes function encode_bits64(uint64 n) internal pure returns (bytes memory) { bytes memory buf = new bytes(8); uint64 tmp = n; for (uint64 i = 0; i < 8; i++) { // Little endian buf[i] = bytes1(uint8(tmp & 0xFF)); tmp = tmp >> 8; } return buf; } /// @notice Encode fixed uint64. /// @param n Number /// @return Marshaled bytes function encode_fixed64(uint64 n) internal pure returns (bytes memory) { return encode_bits64(n); } /// @notice Encode fixed int64. /// @param n Number /// @return Marshaled bytes function encode_sfixed64(int64 n) internal pure returns (bytes memory) { return encode_bits64(uint64(n)); } /// @notice Decode fixed 32-bit int. /// @param n Number /// @return Marshaled bytes function encode_bits32(uint32 n) internal pure returns (bytes memory) { bytes memory buf = new bytes(4); uint64 tmp = n; for (uint64 i = 0; i < 4; i++) { // Little endian buf[i] = bytes1(uint8(tmp & 0xFF)); tmp = tmp >> 8; } return buf; } /// @notice Encode fixed uint32. /// @param n Number /// @return Marshaled bytes function encode_fixed32(uint32 n) internal pure returns (bytes memory) { return encode_bits32(n); } /// @notice Encode fixed int32. /// @param n Number /// @return Marshaled bytes function encode_sfixed32(int32 n) internal pure returns (bytes memory) { return encode_bits32(uint32(n)); } /// @notice Encode length-delimited field. /// @param b Bytes /// @return Marshaled bytes function encode_length_delimited(bytes memory b) internal pure returns (bytes memory) { // Length-delimited fields begin with a varint of the number of bytes that follow bytes memory length_buf = encode_uint64(uint64(b.length)); bytes memory buf = new bytes(b.length + length_buf.length); for (uint64 i = 0; i < length_buf.length; i++) { buf[i] = length_buf[i]; } for (uint64 i = 0; i < b.length; i++) { buf[i + length_buf.length] = b[i]; } return buf; } /// @notice Encode string. /// @param s String /// @return Marshaled bytes function encode_string(string memory s) internal pure returns (bytes memory) { return encode_length_delimited(bytes(s)); } /// @notice Encode bytes array. /// @param b Bytes /// @return Marshaled bytes function encode_bytes(bytes memory b) internal pure returns (bytes memory) { return encode_length_delimited(b); } /// @notice Encode embedded message. /// @param m Message /// @return Marshaled bytes function encode_embedded_message(bytes memory m) internal pure returns (bytes memory) { return encode_length_delimited(m); } /// @notice Encode packed repeated field. /// @param b Bytes /// @return Marshaled bytes function encode_packed_repeated(bytes memory b) internal pure returns (bytes memory) { return encode_length_delimited(b); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.9; // Reference: https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf library Sha512 { // @notice: The message, M, shall be padded before hash computation begins. // The purpose of this padding is to ensure that the padded message is a multiple of 1024 bits. // @param message input raw message bytes // @return padded message bytes function preprocess(bytes memory message) internal pure returns (bytes memory) { uint256 padding = 128 - (message.length % 128); if (message.length % 128 >= 112) { padding = 256 - (message.length % 128); } bytes memory result = new bytes(message.length + padding); for (uint256 i = 0; i < message.length; i++) { result[i] = message[i]; } result[message.length] = 0x80; uint128 bitSize = uint128(message.length * 8); bytes memory bitlength = abi.encodePacked(bitSize); for (uint256 index = 0; index < bitlength.length; index++) { result[result.length - 1 - index] = bitlength[ bitlength.length - 1 - index ]; } return result; } function bytesToBytes8(bytes memory b, uint256 offset) internal pure returns (bytes8) { bytes8 out; for (uint256 i = 0; i < 8; i++) { out |= bytes8(b[offset + i] & 0xFF) >> (i * 8); } return out; } function cutBlock(bytes memory data, uint256 blockIndex) internal pure returns (uint64[16] memory) { uint64[16] memory result; for (uint8 r = 0; r < result.length; r++) { result[r] = uint64(bytesToBytes8(data, blockIndex * 128 + r * 8)); } return result; } // This section defines the functions that are used by sha-512. // https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf#page=15 // @notice: Thus, ROTR(x, n) is equivalent to a circular shift (rotation) of x by n positions to the right. // @param x input num // @param n num of positions to circular shift // @return uint64 function ROTR(uint64 x, uint256 n) internal pure returns (uint64) { return (x << (64 - n)) + (x >> n); } // @notice: The right shift operation SHR n(x), where x is a w-bit word and n is an integer with 0 <= n < w, is defined by SHR(x, n) = x >> n. // @param x input num // @param n num of positions to shift // @return uint64 function SHR(uint64 x, uint256 n) internal pure returns (uint64) { return uint64(x >> n); } // @notice: Ch(x, y, z) = (x ^ y) ⊕ (﹁ x ^ z) // @param x x // @param y y // @param z z // @return uint64 function Ch( uint64 x, uint64 y, uint64 z ) internal pure returns (uint64) { return (x & y) ^ ((x ^ 0xffffffffffffffff) & z); } // @notice: Maj(x, y, z) = (x ^ y) ⊕ (x ^ z) ⊕ (y ^ z) // @param x x // @param y y // @param z z // @return uint64 function Maj( uint64 x, uint64 y, uint64 z ) internal pure returns (uint64) { return (x & y) ^ (x & z) ^ (y & z); } // @notice: sigma0(x) = ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39) // @param x x // @return uint64 function sigma0(uint64 x) internal pure returns (uint64) { return ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39); } // @notice: sigma1(x) = ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41) // @param x x // @return uint64 function sigma1(uint64 x) internal pure returns (uint64) { return ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41); } // @notice: gamma0(x) = OTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7) // @param x x // @return uint64 function gamma0(uint64 x) internal pure returns (uint64) { return ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7); } // @notice: gamma1(x) = ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6) // @param x x // @return uint64 function gamma1(uint64 x) internal pure returns (uint64) { return ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6); } struct FuncVar { uint64 a; uint64 b; uint64 c; uint64 d; uint64 e; uint64 f; uint64 g; uint64 h; } // @notice Calculate the SHA512 of input data. // @param data input data bytes // @return 512 bits hash result function hash(bytes memory data) external pure returns (uint64[8] memory) { uint64[8] memory H = [ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 ]; unchecked { uint64 T1; uint64 T2; uint64[80] memory W; FuncVar memory fvar; uint64[80] memory K = [ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 ]; bytes memory blocks = preprocess(data); for (uint256 j = 0; j < blocks.length / 128; j++) { uint64[16] memory M = cutBlock(blocks, j); fvar.a = H[0]; fvar.b = H[1]; fvar.c = H[2]; fvar.d = H[3]; fvar.e = H[4]; fvar.f = H[5]; fvar.g = H[6]; fvar.h = H[7]; for (uint256 i = 0; i < 80; i++) { if (i < 16) { W[i] = M[i]; } else { W[i] = gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]; } T1 = fvar.h + sigma1(fvar.e) + Ch(fvar.e, fvar.f, fvar.g) + K[i] + W[i]; T2 = sigma0(fvar.a) + Maj(fvar.a, fvar.b, fvar.c); fvar.h = fvar.g; fvar.g = fvar.f; fvar.f = fvar.e; fvar.e = fvar.d + T1; fvar.d = fvar.c; fvar.c = fvar.b; fvar.b = fvar.a; fvar.a = T1 + T2; } H[0] = H[0] + fvar.a; H[1] = H[1] + fvar.b; H[2] = H[2] + fvar.c; H[3] = H[3] + fvar.d; H[4] = H[4] + fvar.e; H[5] = H[5] + fvar.f; H[6] = H[6] + fvar.g; H[7] = H[7] + fvar.h; } } return H; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.9; library Ed25519_pow { // Computes (v^(2^250-1), v^11) mod p function pow22501(uint256 v) external pure returns (uint256 p22501, uint256 p11) { p11 = mulmod(v, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); p22501 = mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); p22501 = mulmod( mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); p11 = mulmod(p22501, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); p22501 = mulmod( mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed ); uint256 a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); uint256 b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "frame-verifier/=lib/frame-verifier/src/", "solady/=lib/solady/src/", "wormhole/=lib/wormhole/ethereum/contracts/", "erc6551/=lib/erc6551/src/", "farcaster/=lib/farcaster/src/", "account-abstraction/=lib/account-abstraction/contracts/", "farcaster-solidity/=lib/farcaster-solidity/contracts/", "@openzeppelin/=lib/erc6551/lib/openzeppelin-contracts/", "chainlink-brownie-contracts/=lib/farcaster/lib/chainlink-brownie-contracts/", "chainlink/=lib/farcaster/lib/chainlink-brownie-contracts/contracts/src/", "erc4626-tests/=lib/farcaster/lib/openzeppelin-latest/lib/erc4626-tests/", "halmos-cheatcodes/=lib/farcaster/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/farcaster/lib/openzeppelin-contracts/", "openzeppelin-latest/=lib/farcaster/lib/openzeppelin-latest/", "openzeppelin/=lib/farcaster/lib/openzeppelin-contracts/", "solmate/=lib/farcaster/lib/solmate/", "@lazyledger/protobuf3-solidity-lib/=lib/protobuf3-solidity-lib/", "protobuf3-solidity-lib/=lib/protobuf3-solidity-lib/contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "lib/farcaster-solidity/contracts/libraries/Blake3.sol": { "Blake3": "0x33937f3b8a9107e409931b70478ae716cb51aee8" }, "lib/farcaster-solidity/contracts/libraries/Ed25519.sol": { "Ed25519": "0xfa7321696663ea6b9c8d4d3c892c1176e2587a39" }, "lib/farcaster-solidity/contracts/libraries/Ed25519_pow.sol": { "Ed25519_pow": "0xb4e22f10318492b7bbd160d736f708c1f23df021" }, "lib/farcaster-solidity/contracts/libraries/Sha512.sol": { "Sha512": "0x3c25e1bf271cc1d1ddc10c55c836c4ec727c20aa" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"InvalidButtonIndex","type":"error"},{"inputs":[],"name":"InvalidKey","type":"error"},{"inputs":[],"name":"InvalidMessage","type":"error"},{"inputs":[],"name":"InvalidMessageHash","type":"error"},{"inputs":[],"name":"InvalidMessageType","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureScheme","type":"error"},{"inputs":[],"name":"InvalidUrl","type":"error"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"}],"name":"validateMessage","outputs":[{"components":[{"components":[{"internalType":"enum MessageType","name":"type_","type":"uint8"},{"internalType":"uint64","name":"fid","type":"uint64"},{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"enum FarcasterNetwork","name":"network","type":"uint8"},{"components":[{"internalType":"string","name":"embeds_deprecated","type":"string"},{"internalType":"uint64[]","name":"mentions","type":"uint64[]"},{"components":[{"internalType":"uint64","name":"fid","type":"uint64"},{"internalType":"bytes","name":"hash_","type":"bytes"}],"internalType":"struct CastId","name":"parent_cast_id","type":"tuple"},{"internalType":"string","name":"text","type":"string"},{"internalType":"uint32[]","name":"mentions_positions","type":"uint32[]"},{"components":[{"internalType":"string","name":"url","type":"string"},{"components":[{"internalType":"uint64","name":"fid","type":"uint64"},{"internalType":"bytes","name":"hash_","type":"bytes"}],"internalType":"struct CastId","name":"cast_id","type":"tuple"}],"internalType":"struct Embed[]","name":"embeds","type":"tuple[]"},{"internalType":"string","name":"parent_url","type":"string"}],"internalType":"struct CastAddBody","name":"cast_add_body","type":"tuple"},{"internalType":"bool","name":"empty_cast_remove_body","type":"bool"},{"components":[{"internalType":"enum ReactionType","name":"type_","type":"uint8"},{"components":[{"internalType":"uint64","name":"fid","type":"uint64"},{"internalType":"bytes","name":"hash_","type":"bytes"}],"internalType":"struct CastId","name":"target_cast_id","type":"tuple"},{"internalType":"string","name":"target_url","type":"string"}],"internalType":"struct ReactionBody","name":"reaction_body","type":"tuple"},{"internalType":"bool","name":"empty","type":"bool"},{"components":[{"internalType":"bytes","name":"address_","type":"bytes"},{"internalType":"bytes","name":"eth_signature","type":"bytes"},{"internalType":"bytes","name":"block_hash","type":"bytes"},{"internalType":"uint32","name":"verification_type","type":"uint32"},{"internalType":"uint32","name":"chain_id","type":"uint32"}],"internalType":"struct VerificationAddEthAddressBody","name":"verification_add_eth_address_body","type":"tuple"},{"internalType":"bool","name":"empty_verification_remove_body","type":"bool"},{"internalType":"bool","name":"deprecated_signer_add_body","type":"bool"},{"internalType":"bool","name":"user_data_body","type":"bool"},{"internalType":"bool","name":"deprecated_signer_remove_body","type":"bool"},{"components":[{"internalType":"string","name":"type_","type":"string"},{"internalType":"uint32","name":"displayTimestamp","type":"uint32"},{"internalType":"uint64","name":"target_fid","type":"uint64"}],"internalType":"struct LinkBody","name":"link_body","type":"tuple"},{"internalType":"bool","name":"empty_username_proof_body","type":"bool"},{"components":[{"internalType":"bytes","name":"url","type":"bytes"},{"internalType":"uint32","name":"button_index","type":"uint32"},{"components":[{"internalType":"uint64","name":"fid","type":"uint64"},{"internalType":"bytes","name":"hash_","type":"bytes"}],"internalType":"struct CastId","name":"cast_id","type":"tuple"}],"internalType":"struct FrameActionBody","name":"frame_action_body","type":"tuple"}],"internalType":"struct MessageData","name":"data","type":"tuple"},{"internalType":"bytes","name":"hash_","type":"bytes"},{"internalType":"enum HashScheme","name":"hash_scheme","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"enum SignatureScheme","name":"signature_scheme","type":"uint8"},{"internalType":"bytes","name":"signer","type":"bytes"},{"internalType":"bytes","name":"data_bytes","type":"bytes"}],"internalType":"struct Message","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615529806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063277e661d14610030575b600080fd5b61004361003e366004614a1b565b610059565b6040516100509190614e5f565b60405180910390f35b61006161478a565b60008061007160008586516103c0565b92505091508161009457604051636eca2e4b60e01b815260040160405180910390fd5b60006100a38260000151610551565b905060007333937f3b8a9107e409931b70478ae716cb51aee863227bb04d8360146040518363ffffffff1660e01b81526004016100e19291906150a0565b600060405180830381865af41580156100fe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261012691908101906150c8565b905082602001518051906020012081805190602001201461015a57604051638b56642d60e01b815260040160405180910390fd5b505060608101516020810151604082015160a08401519192909160009073fa7321696663ea6b9c8d4d3c892c1176e2587a3990632bf6eda89061019c90615135565b868689602001516040518563ffffffff1660e01b81526004016101c2949392919061515c565b602060405180830381865af41580156101df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610203919061518b565b90508061022357604051638baa579f60e01b815260040160405180910390fd5b505082516020015160a084015160405163561a662d60e11b8152600094506ffc1237824fb747abde0ff18990e59b7e935063ac34cc5a926102689290916004016151b4565b6040805180830381865afa158015610284573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a891906151d6565b90506001815160028111156102bf576102bf614a9a565b146102dd57604051630eda9c3d60e31b815260040160405180910390fd5b6001826080015160028111156102f5576102f5614a9a565b1461031357604051632171ecf960e01b815260040160405180910390fd5b600d825151600d81111561032957610329614a9a565b1461034757604051635b60892f60e01b815260040160405180910390fd5b81516101e00151515161010010156103725760405163e7bc872f60e01b815260040160405180910390fd5b81516101e0015160200151600163ffffffff82161080610398575060048163ffffffff16115b156103b657604051639a759aa960e01b815260040160405180910390fd5b5090949350505050565b6000806103cb61478a565b6103d361478a565b6000876001600160401b0381166103ea8883615257565b6001600160401b03161015610409576000955093509091506105489050565b6001600160401b03871661041d8a8361527e565b6001600160401b0316101561050b57600080600061043b848c61080f565b91965091945090925090508261045f57506000975091955092935061054892505050565b6007826001600160401b0316111561048557506000975091955092935061054892505050565b846001600160401b0316826001600160401b0316116104b257506000975091955092935061054892505050565b6104bc8282610901565b9250826104d757506000975091955092935061054892505050565b6104e4848c8c858a6109cb565b945092508261050157506000975091955092935061054892505050565b5092506104099050565b610515878a615257565b6001600160401b0316816001600160401b03161461053d576000955093509091506105489050565b600195509350909150505b93509350939050565b606060008260000151600d81111561056b5761056b614a9a565b6001600160401b031660000361058f5760408051600081526020810190915261059b565b61059b60016000610ad3565b905060008360000151600d8111156105b5576105b5614a9a565b6001600160401b03166000036105d9576040805160008152602081019091526105f5565b83516105f590600d8111156105f0576105f0614a9a565b610afb565b9050600084602001516001600160401b03166000036106225760408051600081526020810190915261062e565b61062e60026000610ad3565b9050600085602001516001600160401b031660000361065b57604080516000815260208101909152610668565b6106688660200151610b09565b90506000866040015163ffffffff166001600160401b031660000361069b576040805160008152602081019091526106a7565b6106a760036000610ad3565b90506000876040015163ffffffff166001600160401b03166000036106da576040805160008152602081019091526106e7565b6106e78860400151610b14565b905060008860600151600381111561070157610701614a9a565b6001600160401b031660000361072557604080516000815260208101909152610731565b61073160046000610ad3565b905060008960600151600381111561074b5761074b614a9a565b6001600160401b031660000361076f57604080516000815260208101909152610788565b6107888a6060015160038111156105f0576105f0614a9a565b9050600061079c60108c6101e00151610b25565b805160208083015160408085015190519495506000946107bd94930161529e565b60405160208183030381529060405290508989898989898989886040516020016107ef999897969594939291906152e1565b6040516020818303038152906040529a5050505050505050505050919050565b60008060008060008060006108248989610bdd565b925092509250826108445750600095509350849250600691506108f89050565b600381901c671fffffffffffffff1660078216600681106108785760008460006006985098509850985050505050506108f8565b6000816001600160401b0316600681111561089557610895614a9a565b905060038160068111156108ab576108ab614a9a565b14806108c8575060048160068111156108c6576108c6614a9a565b145b156108e7576000856000600699509950995099505050505050506108f8565b600199509397509095509193505050505b92959194509250565b6000826001600160401b03166001036109315760025b82600681111561092957610929614a9a565b1490506109c5565b826001600160401b0316600203610949576002610917565b826001600160401b0316600303610961576000610917565b826001600160401b0316600403610979576002610917565b826001600160401b0316600503610991576000610917565b826001600160401b03166006036109a9576002610917565b826001600160401b03166007036109c1576002610917565b5060005b92915050565b600080866001600160401b038516600103610a0e5760006109ed828987610d88565b9250905080610a025750600092509050610ac9565b50600192509050610ac9565b846001600160401b0316600203610a2c5760006109ed828987610e15565b846001600160401b0316600303610a4a5760006109ed828987610f5e565b846001600160401b0316600403610a685760006109ed828987611017565b846001600160401b0316600503610a865760006109ed828987611146565b846001600160401b0316600603610aa45760006109ed8289876111f0565b846001600160401b0316600703610ac25760006109ed82898761131f565b6000925090505b9550959350505050565b60606807fffffffffffffff8600384901b1682176000610af28261144e565b95945050505050565b60606109c58260030b61144e565b60606109c58261144e565b60606109c58263ffffffff1661144e565b610b4960405180606001604052806060815260200160608152602001606081525090565b6000610b54836115a8565b805190915060006001600160401b038216610b7d57604080516000815260208101909152610b88565b610b88866002610ad3565b9050600080836001600160401b031611610bb057604080516000815260208101909152610bb9565b610bb983610b09565b60408051606081018252938452602084019190915282019390935295945050505050565b60008060008060005b600a6001600160401b0382161015610cd3578551610c048883615257565b6001600160401b031610610c245760008760009450945094505050610d81565b600086610c31838a615257565b6001600160401b031681518110610c4a57610c4a6153a2565b016020015160f81c9050607f8116610c638360076153b8565b60ff82166001600160401b03919091161b939093179260808216600003610cbe576000836001600160401b0316118015610c9e575060ff8116155b15610cb757600089600096509650965050505050610d81565b5050610cd3565b50508080610ccb906153e3565b915050610be6565b600a6001600160401b03821610610cf65760008760009450945094505050610d81565b610d026001600a61527e565b6001600160401b0316816001600160401b031603610d6057600186610d27838a615257565b6001600160401b031681518110610d4057610d406153a2565b016020015160f81c1115610d605760008760009450945094505050610d81565b6001610d6c8289615257565b610d77906001615257565b8394509450945050505b9250925092565b600080600080610d98878761172b565b909850909250905081610db357600087935093505050610e0d565b806001600160401b0316600003610dd257600087935093505050610e0d565b610dda6147cd565b610de5888884611747565b909950909350905082610e015760008894509450505050610e0d565b85525060019250859150505b935093915050565b600080600080610e25878761172b565b909850909250905081610e4057600087935093505050610e0d565b806001600160401b0316600003610e5f57600087935093505050610e0d565b806001600160401b03166001600160401b03811115610e8057610e806149ae565b6040519080825280601f01601f191660200182016040528015610eaa576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b03161015610f445786610ed8828a615257565b6001600160401b031681518110610ef157610ef16153a2565b602001015160f81c60f81b8660200151826001600160401b031681518110610f1b57610f1b6153a2565b60200101906001600160f81b031916908160001a90535080610f3c816153e3565b915050610eb3565b50610f4f8188615257565b60019890975095505050505050565b600080600080610f6e8787611892565b909850909250905081610f8957600087935093505050610e0d565b8060030b600003610fa257600087935093505050610e0d565b60008160030b1280610fb7575060018160030b135b15610fca57600087935093505050610e0d565b8060030b6001811115610fdf57610fdf614a9a565b85604001906001811115610ff557610ff5614a9a565b9081600181111561100857611008614a9a565b90525060019795505050505050565b600080600080611027878761172b565b90985090925090508161104257600087935093505050610e0d565b806001600160401b031660000361106157600087935093505050610e0d565b806001600160401b03166001600160401b03811115611082576110826149ae565b6040519080825280601f01601f1916602001820160405280156110ac576020820181803683370190505b50606086015260005b816001600160401b0316816001600160401b03161015610f4457866110da828a615257565b6001600160401b0316815181106110f3576110f36153a2565b602001015160f81c60f81b8660600151826001600160401b03168151811061111d5761111d6153a2565b60200101906001600160f81b031916908160001a9053508061113e816153e3565b9150506110b5565b6000806000806111568787611892565b90985090925090508161117157600087935093505050610e0d565b8060030b60000361118a57600087935093505050610e0d565b60008160030b128061119f575060028160030b135b156111b257600087935093505050610e0d565b8060030b60028111156111c7576111c7614a9a565b856080019060028111156111dd576111dd614a9a565b9081600281111561100857611008614a9a565b600080600080611200878761172b565b90985090925090508161121b57600087935093505050610e0d565b806001600160401b031660000361123a57600087935093505050610e0d565b806001600160401b03166001600160401b0381111561125b5761125b6149ae565b6040519080825280601f01601f191660200182016040528015611285576020820181803683370190505b5060a086015260005b816001600160401b0316816001600160401b03161015610f4457866112b3828a615257565b6001600160401b0316815181106112cc576112cc6153a2565b602001015160f81c60f81b8660a00151826001600160401b0316815181106112f6576112f66153a2565b60200101906001600160f81b031916908160001a90535080611317816153e3565b91505061128e565b60008060008061132f878761172b565b90985090925090508161134a57600087935093505050610e0d565b806001600160401b031660000361136957600087935093505050610e0d565b806001600160401b03166001600160401b0381111561138a5761138a6149ae565b6040519080825280601f01601f1916602001820160405280156113b4576020820181803683370190505b5060c086015260005b816001600160401b0316816001600160401b03161015610f4457866113e2828a615257565b6001600160401b0316815181106113fb576113fb6153a2565b602001015160f81c60f81b8660c00151826001600160401b031681518110611425576114256153a2565b60200101906001600160f81b031916908160001a90535080611446816153e3565b9150506113bd565b60608160015b607f826001600160401b0316111561148a576007826001600160401b0316901c91506001816114839190615257565b9050611454565b6000816001600160401b03166001600160401b038111156114ad576114ad6149ae565b6040519080825280601f01601f1916602001820160405280156114d7576020820181803683370190505b50905084925060005b826001600160401b0316816001600160401b031610156115595783607f1660801760f81b82826001600160401b03168151811061151f5761151f6153a2565b60200101906001600160f81b031916908160001a9053506007846001600160401b0316901c93508080611551906153e3565b9150506114e0565b50607f60f81b8161156b60018561527e565b6001600160401b031681518110611584576115846153a2565b0160200180519091166001600160f81b03191690600082901a905350949350505050565b6060600080836000015151116115cc576040805160008152602081019091526115d8565b6115d860016002610ad3565b9050600080846000015151116115fc57604080516000815260208101909152611608565b83515161160890610b09565b90506000808560000151511161162c5760408051600081526020810190915261162f565b84515b90506000856020015163ffffffff166001600160401b03166000036116625760408051600081526020810190915261166e565b61166e60026000610ad3565b90506000866020015163ffffffff166001600160401b03166000036116a1576040805160008152602081019091526116ae565b6116ae8760200151610b14565b905060006116c1600389604001516118a1565b805160208083015160408085015190519495506000946116e294930161529e565b604051602081830303815290604052905086868686868560405160200161170e96959493929190615409565b604051602081830303815290604052975050505050505050919050565b600080600061173a85856118d0565b9250925092509250925092565b6000806117526147cd565b61175a6147cd565b6000876001600160401b0381166117718883615257565b6001600160401b03161015611790576000955093509091506105489050565b6001600160401b0387166117a48a8361527e565b6001600160401b0316101561050b5760008060006117c2848c61080f565b9196509194509092509050826117e657506000975091955092935061054892505050565b6010826001600160401b0316111561180c57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161183957506000975091955092935061054892505050565b6118438282611967565b92508261185e57506000975091955092935061054892505050565b61186b848c8c858a611ae9565b945092508261188857506000975091955092935061054892505050565b5092506117909050565b600080600061173a8585611ccd565b6118c560405180606001604052806060815260200160608152602001606081525090565b6000610b5483611d2c565b6000806000806000806118e38888610bdd565b925092509250826118ff5750600094509250839150610d819050565b816001600160401b03168183016001600160401b0316101561192c5750600094509250839150610d819050565b86516119388383615257565b6001600160401b031611156119585750600094509250839150610d819050565b60019891975095509350505050565b6000826001600160401b0316600103611981576000610917565b826001600160401b0316600203611999576000610917565b826001600160401b03166003036119b1576000610917565b826001600160401b03166004036119c9576000610917565b826001600160401b03166005036119e1576002610917565b826001600160401b03166006036119f9576000610917565b826001600160401b0316600703611a11576002610917565b826001600160401b0316600803611a29576000610917565b826001600160401b0316600903611a41576002610917565b826001600160401b0316600a03611a59576000610917565b826001600160401b0316600b03611a71576000610917565b826001600160401b0316600c03611a89576000610917565b826001600160401b0316600d03611aa1576000610917565b826001600160401b0316600e03611ab9576002610917565b826001600160401b0316600f03611ad1576000610917565b826001600160401b03166010036109c1576002610917565b600080866001600160401b038516600103611b0b5760006109ed828987611e5e565b846001600160401b0316600203611b295760006109ed828987611f05565b846001600160401b0316600303611b475760006109ed828987611f6c565b846001600160401b0316600403611b655760006109ed828987611fcd565b846001600160401b0316600503611b835760006109ed828987612077565b846001600160401b0316600603611ba15760006109ed828987612105565b846001600160401b0316600703611bbf5760006109ed82898761215e565b846001600160401b0316600803611bdd5760006109ed8289876121ec565b846001600160401b0316600903611bfb5760006109ed828987612245565b846001600160401b0316600a03611c195760006109ed8289876122d4565b846001600160401b0316600b03611c375760006109ed82898761232e565b846001600160401b0316600c03611c555760006109ed828987612388565b846001600160401b0316600d03611c735760006109ed8289876123e2565b846001600160401b0316600e03611c915760006109ed82898761243c565b846001600160401b0316600f03611caf5760006109ed8289876124e0565b846001600160401b0316601003610ac25760006109ed82898761253a565b600080600080600080611ce08888610bdd565b92509250925082611cfc5750600094509250839150610d819050565b6001603f82901c166000036119585767ffffffff000000008116156119585750600094509250839150610d819050565b6060600082600001516001600160401b0316600003611d5957604080516000815260208101909152611d65565b611d6560016000610ad3565b9050600083600001516001600160401b0316600003611d9257604080516000815260208101909152611d9d565b8351611d9d90610b09565b905060008085602001515111611dc157604080516000815260208101909152611dcc565b611dcc600280610ad3565b905060008086602001515111611df057604080516000815260208101909152611dfe565b611dfe866020015151610b09565b905060008087602001515111611e2257604080516000815260208101909152611e28565b86602001515b90508484848484604051602001611e43959493929190615488565b60405160208183030381529060405295505050505050919050565b600080600080611e6e8787611892565b909850909250905081611e8957600087935093505050610e0d565b8060030b600003611ea257600087935093505050610e0d565b60008160030b1280611eb75750600d8160030b135b15611eca57600087935093505050610e0d565b8060030b600d811115611edf57611edf614a9a565b8590600d811115611ef257611ef2614a9a565b9081600d81111561100857611008614a9a565b600080600080611f1587876125c9565b909850909250905081611f3057600087935093505050610e0d565b806001600160401b0316600003611f4f57600087935093505050610e0d565b6001600160401b0316602094909401939093525060019492505050565b600080600080611f7c87876125f8565b909850909250905081611f9757600087935093505050610e0d565b8063ffffffff16600003611fb357600087935093505050610e0d565b63ffffffff16604094909401939093525060019492505050565b600080600080611fdd8787611892565b909850909250905081611ff857600087935093505050610e0d565b8060030b60000361201157600087935093505050610e0d565b60008160030b1280612026575060038160030b135b1561203957600087935093505050610e0d565b8060030b600381111561204e5761204e614a9a565b8560600190600381111561206457612064614a9a565b9081600381111561100857611008614a9a565b600080600080612087878761172b565b9098509092509050816120a257600087935093505050610e0d565b806001600160401b03166000036120c157600087935093505050610e0d565b6120c9614883565b6120d4888884612648565b9099509093509050826120f05760008894509450505050610e0d565b60809590950194909452506001959350505050565b6000806000806121158787612793565b90985090925090508161213057600087935093505050610e0d565b80151560000361214857600087935093505050610e0d565b151560a094909401939093525060019492505050565b60008060008061216e878761172b565b90985090925090508161218957600087935093505050610e0d565b806001600160401b03166000036121a857600087935093505050610e0d565b6121b06148d9565b6121bb888884612819565b9099509093509050826121d75760008894509450505050610e0d565b60c09590950194909452506001959350505050565b6000806000806121fc8787612793565b90985090925090508161221757600087935093505050610e0d565b80151560000361222f57600087935093505050610e0d565b151560e094909401939093525060019492505050565b600080600080612255878761172b565b90985090925090508161227057600087935093505050610e0d565b806001600160401b031660000361228f57600087935093505050610e0d565b612297614914565b6122a2888884612964565b9099509093509050826122be5760008894509450505050610e0d565b6101009590950194909452506001959350505050565b6000806000806122e48787612793565b9098509092509050816122ff57600087935093505050610e0d565b80151560000361231757600087935093505050610e0d565b151561012094909401939093525060019492505050565b60008060008061233e8787612793565b90985090925090508161235957600087935093505050610e0d565b80151560000361237157600087935093505050610e0d565b151561014094909401939093525060019492505050565b6000806000806123988787612793565b9098509092509050816123b357600087935093505050610e0d565b8015156000036123cb57600087935093505050610e0d565b151561016094909401939093525060019492505050565b6000806000806123f28787612793565b90985090925090508161240d57600087935093505050610e0d565b80151560000361242557600087935093505050610e0d565b151561018094909401939093525060019492505050565b60008060008061244c878761172b565b90985090925090508161246757600087935093505050610e0d565b806001600160401b031660000361248657600087935093505050610e0d565b60408051606080820183528152600060208201819052918101919091526124ae888884612aaf565b9099509093509050826124ca5760008894509450505050610e0d565b6101a09590950194909452506001959350505050565b6000806000806124f08787612793565b90985090925090508161250b57600087935093505050610e0d565b80151560000361252357600087935093505050610e0d565b15156101c094909401939093525060019492505050565b60008060008061254a878761172b565b90985090925090508161256557600087935093505050610e0d565b806001600160401b031660000361258457600087935093505050610e0d565b61258c61494f565b612597888884612c1c565b9099509093509050826125b35760008894509450505050610e0d565b6101e09590950194909452506001959350505050565b6000806000806000806125dc8888610bdd565b925092509250826119585750600094509250839150610d819050565b60008060008060008061260b8888610bdd565b925092509250826126275750600094509250839150610d819050565b67ffffffff000000008116156119585750600094509250839150610d819050565b600080612653614883565b61265b614883565b6000876001600160401b0381166126728883615257565b6001600160401b03161015612691576000955093509091506105489050565b6001600160401b0387166126a58a8361527e565b6001600160401b0316101561050b5760008060006126c3848c61080f565b9196509194509092509050826126e757506000975091955092935061054892505050565b6007826001600160401b0316111561270d57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161273a57506000975091955092935061054892505050565b6127448282612d67565b92508261275f57506000975091955092935061054892505050565b61276c848c8c858a612de1565b945092508261278957506000975091955092935061054892505050565b5092506126919050565b6000806000806000806127a68888610bdd565b925092509250826127c25750600094509250839150610d819050565b6001816001600160401b031611156127e55750600094509250839150610d819050565b806001600160401b0316600003612808575060019450925060009150610d819050565b506001979096508795509350505050565b6000806128246148d9565b61282c6148d9565b6000876001600160401b0381166128438883615257565b6001600160401b03161015612862576000955093509091506105489050565b6001600160401b0387166128768a8361527e565b6001600160401b0316101561050b576000806000612894848c61080f565b9196509194509092509050826128b857506000975091955092935061054892505050565b6003826001600160401b031611156128de57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161290b57506000975091955092935061054892505050565b6129158282612eb7565b92508261293057506000975091955092935061054892505050565b61293d848c8c858a612f01565b945092508261295a57506000975091955092935061054892505050565b5092506128629050565b60008061296f614914565b612977614914565b6000876001600160401b03811661298e8883615257565b6001600160401b031610156129ad576000955093509091506105489050565b6001600160401b0387166129c18a8361527e565b6001600160401b0316101561050b5760008060006129df848c61080f565b919650919450909250905082612a0357506000975091955092935061054892505050565b6005826001600160401b03161115612a2957506000975091955092935061054892505050565b846001600160401b0316826001600160401b031611612a5657506000975091955092935061054892505050565b612a608282612f5f565b925082612a7b57506000975091955092935061054892505050565b612a88848c8c858a612fd9565b9450925082612aa557506000975091955092935061054892505050565b5092506129ad9050565b60408051606080820183528082526000602080840182905283850182905284518084018652928352820181905292810183905282919082876001600160401b038116612afb8883615257565b6001600160401b03161015612b1a576000955093509091506105489050565b6001600160401b038716612b2e8a8361527e565b6001600160401b0316101561050b576000806000612b4c848c61080f565b919650919450909250905082612b7057506000975091955092935061054892505050565b6003826001600160401b03161115612b9657506000975091955092935061054892505050565b846001600160401b0316826001600160401b031611612bc357506000975091955092935061054892505050565b612bcd8282613073565b925082612be857506000975091955092935061054892505050565b612bf5848c8c858a6130bd565b9450925082612c1257506000975091955092935061054892505050565b509250612b1a9050565b600080612c2761494f565b612c2f61494f565b6000876001600160401b038116612c468883615257565b6001600160401b03161015612c65576000955093509091506105489050565b6001600160401b038716612c798a8361527e565b6001600160401b0316101561050b576000806000612c97848c61080f565b919650919450909250905082612cbb57506000975091955092935061054892505050565b6003826001600160401b03161115612ce157506000975091955092935061054892505050565b846001600160401b0316826001600160401b031611612d0e57506000975091955092935061054892505050565b612d18828261311b565b925082612d3357506000975091955092935061054892505050565b612d40848c8c858a61314d565b9450925082612d5d57506000975091955092935061054892505050565b509250612c659050565b6000826001600160401b0316600103612d81576002610917565b826001600160401b0316600203612d99576002610917565b826001600160401b0316600303612db1576002610917565b826001600160401b0316600403612dc9576002610917565b826001600160401b0316600503610991576002610917565b600080866001600160401b038516600103612e035760006109ed8289876131ab565b846001600160401b0316600203612e215760006109ed8289876131fb565b846001600160401b0316600303612e3f5760006109ed828987613404565b846001600160401b0316600403612e5d5760006109ed82898761349f565b846001600160401b0316600503612e7b5760006109ed8289876134f6565b846001600160401b0316600603612e995760006109ed8289876136bb565b846001600160401b0316600703610ac25760006109ed82898761391e565b6000826001600160401b0316600103612ed1576000610917565b826001600160401b0316600203612ee9576002610917565b826001600160401b03166003036109c1576002610917565b600080866001600160401b038516600103612f235760006109ed828987613975565b846001600160401b0316600203612f415760006109ed828987613a09565b846001600160401b0316600303610ac25760006109ed828987613aa4565b6000826001600160401b0316600103612f79576002610917565b826001600160401b0316600203612f91576002610917565b826001600160401b0316600303612fa9576002610917565b826001600160401b0316600403612fc1576000610917565b826001600160401b03166005036109c1576000610917565b600080866001600160401b038516600103612ffb5760006109ed828987613afb565b846001600160401b03166002036130195760006109ed828987613c27565b846001600160401b03166003036130375760006109ed828987613d56565b846001600160401b03166004036130555760006109ed828987613e85565b846001600160401b0316600503610ac25760006109ed828987613ee6565b6000826001600160401b031660010361308d576002610917565b826001600160401b03166002036130a5576000610917565b826001600160401b03166003036109c1576000610917565b600080866001600160401b0385166001036130df5760006109ed8289876131ab565b846001600160401b03166002036130fd5760006109ed828987613f47565b846001600160401b0316600303610ac25760006109ed828987613fa8565b6000826001600160401b0316600103613135576002610917565b826001600160401b0316600203612ee9576000610917565b600080866001600160401b03851660010361316f5760006109ed82898761400f565b846001600160401b031660020361318d5760006109ed828987613f47565b846001600160401b0316600303610ac25760006109ed828987613404565b600080600060606131bc878761413b565b9098509092509050816131d757600087935093505050610e0d565b80516000036131ee57600087935093505050610e0d565b9093525060019492505050565b60008060008061320b87876118d0565b90985090925090508161322657600087935093505050610e0d565b806001600160401b031660000361324557600087935093505050610e0d565b866001600160401b03811661325a8383615257565b6001600160401b031610156132785760008894509450505050610e0d565b60005b6001600160401b03831661328f838b61527e565b6001600160401b031610156132db5760006132aa8a8a6125c9565b909b509095509050846132c85760008a965096505050505050610e0d565b6132d3600183615257565b91505061327b565b806001600160401b03166001600160401b038111156132fc576132fc6149ae565b604051908082528060200260200182016040528015613325578160200160208202803683370190505b506020880152909750879060005b816001600160401b0316816001600160401b031610156133c35760006133598b8b6125c9565b909c509096509050856133785760008b97509750505050505050610e0d565b808960200151836001600160401b031681518110613398576133986153a2565b6001600160401b039092166020928302919091019091015250806133bb816153e3565b915050613333565b506133ce8383615257565b6001600160401b0316896001600160401b0316146133f6576000899550955050505050610e0d565b506001989650505050505050565b600080600080613414878761172b565b90985090925090508161342f57600087935093505050610e0d565b806001600160401b031660000361344e57600087935093505050610e0d565b60408051808201909152600081526060602082015261346e888884614279565b90995090935090508261348a5760008894509450505050610e0d565b60409590950194909452506001959350505050565b600080600060606134b0878761413b565b9098509092509050816134cb57600087935093505050610e0d565b80516000036134e257600087935093505050610e0d565b606094909401939093525060019492505050565b60008060008061350687876118d0565b90985090925090508161352157600087935093505050610e0d565b806001600160401b031660000361354057600087935093505050610e0d565b866001600160401b0381166135558383615257565b6001600160401b031610156135735760008894509450505050610e0d565b60005b6001600160401b03831661358a838b61527e565b6001600160401b031610156135d65760006135a58a8a6125f8565b909b509095509050846135c35760008a965096505050505050610e0d565b6135ce600183615257565b915050613576565b806001600160401b03166001600160401b038111156135f7576135f76149ae565b604051908082528060200260200182016040528015613620578160200160208202803683370190505b506080880152909750879060005b816001600160401b0316816001600160401b031610156133c35760006136548b8b6125f8565b909c509096509050856136735760008b97509750505050505050610e0d565b808960800151836001600160401b031681518110613693576136936153a2565b63ffffffff9092166020928302919091019091015250806136b3816153e3565b91505061362e565b6000808085815b8651886001600160401b031610156137b05760006136e0898961172b565b909a509094509050836136fd576000899550955050505050610e0d565b6001600160401b038916613711828b615257565b6001600160401b03161015613730576000899550955050505050610e0d565b61373a818a615257565b9850613747600183615257565b91508751896001600160401b03161061376057506137b0565b60008061376d8b8b61080f565b919d5091975090925090508561378f5760008b97509750505050505050610e0d565b816001600160401b03166006146137a8575050506137b0565b5050506136c2565b806001600160401b03166001600160401b038111156137d1576137d16149ae565b60405190808252806020026020018201604052801561380a57816020015b6137f7614981565b8152602001906001900390816137ef5790505b5060a0870152909650869060005b816001600160401b0316816001600160401b031610156133f657600061383e8a8a61172b565b909b5090955090508461385c5760008a965096505050505050610e0d565b899350613867614981565b6138728b8b846143e4565b909c509096509050856138915760008b97509750505050505050610e0d565b808960a00151846001600160401b0316815181106138b1576138b16153a2565b60209081029190910101526138c760018561527e565b6001600160401b0316836001600160401b03161015613909576138ea8b8b6125c9565b909c509096509150856139095760008b97509750505050505050610e0d565b50508080613916906153e3565b915050613818565b6000806000606061392f878761413b565b90985090925090508161394a57600087935093505050610e0d565b805160000361396157600087935093505050610e0d565b60c094909401939093525060019492505050565b6000806000806139858787611892565b9098509092509050816139a057600087935093505050610e0d565b8060030b6000036139b957600087935093505050610e0d565b60008160030b12806139ce575060028160030b135b156139e157600087935093505050610e0d565b8060030b60028111156139f6576139f6614a9a565b859060028111156111dd576111dd614a9a565b600080600080613a19878761172b565b909850909250905081613a3457600087935093505050610e0d565b806001600160401b0316600003613a5357600087935093505050610e0d565b604080518082019091526000815260606020820152613a73888884614279565b909950909350905082613a8f5760008894509450505050610e0d565b60209590950194909452506001959350505050565b60008060006060613ab5878761413b565b909850909250905081613ad057600087935093505050610e0d565b8051600003613ae757600087935093505050610e0d565b604094909401939093525060019492505050565b600080600080613b0b878761172b565b909850909250905081613b2657600087935093505050610e0d565b806001600160401b0316600003613b4557600087935093505050610e0d565b806001600160401b03166001600160401b03811115613b6657613b666149ae565b6040519080825280601f01601f191660200182016040528015613b90576020820181803683370190505b50855260005b816001600160401b0316816001600160401b03161015610f445786613bbb828a615257565b6001600160401b031681518110613bd457613bd46153a2565b602001015160f81c60f81b8660000151826001600160401b031681518110613bfe57613bfe6153a2565b60200101906001600160f81b031916908160001a90535080613c1f816153e3565b915050613b96565b600080600080613c37878761172b565b909850909250905081613c5257600087935093505050610e0d565b806001600160401b0316600003613c7157600087935093505050610e0d565b806001600160401b03166001600160401b03811115613c9257613c926149ae565b6040519080825280601f01601f191660200182016040528015613cbc576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b03161015610f445786613cea828a615257565b6001600160401b031681518110613d0357613d036153a2565b602001015160f81c60f81b8660200151826001600160401b031681518110613d2d57613d2d6153a2565b60200101906001600160f81b031916908160001a90535080613d4e816153e3565b915050613cc5565b600080600080613d66878761172b565b909850909250905081613d8157600087935093505050610e0d565b806001600160401b0316600003613da057600087935093505050610e0d565b806001600160401b03166001600160401b03811115613dc157613dc16149ae565b6040519080825280601f01601f191660200182016040528015613deb576020820181803683370190505b50604086015260005b816001600160401b0316816001600160401b03161015610f445786613e19828a615257565b6001600160401b031681518110613e3257613e326153a2565b602001015160f81c60f81b8660400151826001600160401b031681518110613e5c57613e5c6153a2565b60200101906001600160f81b031916908160001a90535080613e7d816153e3565b915050613df4565b600080600080613e9587876125f8565b909850909250905081613eb057600087935093505050610e0d565b8063ffffffff16600003613ecc57600087935093505050610e0d565b63ffffffff16606094909401939093525060019492505050565b600080600080613ef687876125f8565b909850909250905081613f1157600087935093505050610e0d565b8063ffffffff16600003613f2d57600087935093505050610e0d565b63ffffffff16608094909401939093525060019492505050565b600080600080613f5787876125f8565b909850909250905081613f7257600087935093505050610e0d565b8063ffffffff16600003613f8e57600087935093505050610e0d565b63ffffffff16602094909401939093525060019492505050565b600080600080613fb887876125c9565b909850909250905081613fd357600087935093505050610e0d565b806001600160401b0316600003613ff257600087935093505050610e0d565b6001600160401b0316604094909401939093525060019492505050565b60008060008061401f878761172b565b90985090925090508161403a57600087935093505050610e0d565b806001600160401b031660000361405957600087935093505050610e0d565b806001600160401b03166001600160401b0381111561407a5761407a6149ae565b6040519080825280601f01601f1916602001820160405280156140a4576020820181803683370190505b50855260005b816001600160401b0316816001600160401b03161015610f4457866140cf828a615257565b6001600160401b0316815181106140e8576140e86153a2565b602001015160f81c60f81b8660000151826001600160401b031681518110614112576141126153a2565b60200101906001600160f81b031916908160001a90535080614133816153e3565b9150506140aa565b6000806060600080600061414f88886118d0565b9250925092508261417b5760008260405180602001604052806000815250955095509550505050610d81565b6000816001600160401b03166001600160401b0381111561419e5761419e6149ae565b6040519080825280601f01601f1916602001820160405280156141c8576020820181803683370190505b50905060005b826001600160401b0316816001600160401b0316101561425b57886141f38286615257565b6001600160401b03168151811061420c5761420c6153a2565b602001015160f81c60f81b82826001600160401b031681518110614232576142326153a2565b60200101906001600160f81b031916908160001a90535080614253816153e3565b9150506141ce565b5060016142688385615257565b909750955093505050509250925092565b60008061429760408051808201909152600081526060602082015290565b6040805180820190915260008152606060208201526000876001600160401b0381166142c38883615257565b6001600160401b031610156142e2576000955093509091506105489050565b6001600160401b0387166142f68a8361527e565b6001600160401b0316101561050b576000806000614314848c61080f565b91965091945090925090508261433857506000975091955092935061054892505050565b6002826001600160401b0316111561435e57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161438b57506000975091955092935061054892505050565b614395828261452f565b9250826143b057506000975091955092935061054892505050565b6143bd848c8c858a614561565b94509250826143da57506000975091955092935061054892505050565b5092506142e29050565b6000806143ef614981565b6143f7614981565b6000876001600160401b03811661440e8883615257565b6001600160401b0316101561442d576000955093509091506105489050565b6001600160401b0387166144418a8361527e565b6001600160401b0316101561050b57600080600061445f848c61080f565b91965091945090925090508261448357506000975091955092935061054892505050565b6002826001600160401b031611156144a957506000975091955092935061054892505050565b846001600160401b0316826001600160401b0316116144d657506000975091955092935061054892505050565b6144e082826145a1565b9250826144fb57506000975091955092935061054892505050565b614508848c8c858a6145bb565b945092508261452557506000975091955092935061054892505050565b50925061442d9050565b6000826001600160401b0316600103614549576000610917565b826001600160401b03166002036109c1576002610917565b600080866001600160401b0385166001036145835760006109ed8289876145fb565b846001600160401b0316600203610ac25760006109ed82898761465b565b6000826001600160401b0316600103614549576002610917565b600080866001600160401b0385166001036145dd5760006109ed8289876131ab565b846001600160401b0316600203610ac25760006109ed828987613a09565b60008060008061460b87876125c9565b90985090925090508161462657600087935093505050610e0d565b806001600160401b031660000361464557600087935093505050610e0d565b6001600160401b03169093525060019492505050565b60008060008061466b878761172b565b90985090925090508161468657600087935093505050610e0d565b806001600160401b03166000036146a557600087935093505050610e0d565b806001600160401b03166001600160401b038111156146c6576146c66149ae565b6040519080825280601f01601f1916602001820160405280156146f0576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b03161015610f44578661471e828a615257565b6001600160401b031681518110614737576147376153a2565b602001015160f81c60f81b8660200151826001600160401b031681518110614761576147616153a2565b60200101906001600160f81b031916908160001a90535080614782816153e3565b9150506146f9565b6040518060e0016040528061479d6147cd565b81526060602082015260400160008152606060208201526040016000815260200160608152602001606081525090565b60408051610200810182526000808252602082018190529181018290526060810191909152608081016147fe614883565b8152600060208201526040016148126148d9565b815260006020820152604001614826614914565b81526000602082018190526040820181905260608201819052608082015260a00161486a604080516060808201835281526000602082018190529181019190915290565b81526000602082015260400161487e61494f565b905290565b6040518060e0016040528060608152602001606081526020016148b760408051808201909152600081526060602082015290565b8152602001606081526020016060815260200160608152602001606081525090565b6040805160608101909152806000815260200161490760408051808201909152600081526060602082015290565b8152602001606081525090565b6040518060a00160405280606081526020016060815260200160608152602001600063ffffffff168152602001600063ffffffff1681525090565b604080516060808201835281526000602082015290810161487e60408051808201909152600081526060602082015290565b60405180604001604052806060815260200161487e60408051808201909152600081526060602082015290565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156149ec576149ec6149ae565b604052919050565b60006001600160401b03821115614a0d57614a0d6149ae565b50601f01601f191660200190565b600060208284031215614a2d57600080fd5b81356001600160401b03811115614a4357600080fd5b8201601f81018413614a5457600080fd5b8035614a67614a62826149f4565b6149c4565b818152856020838501011115614a7c57600080fd5b81602084016020830137600091810160200191909152949350505050565b634e487b7160e01b600052602160045260246000fd5b600e8110614ac057614ac0614a9a565b9052565b60048110614ac057614ac0614a9a565b60005b83811015614aef578181015183820152602001614ad7565b50506000910152565b60008151808452614b10816020860160208601614ad4565b601f01601f19169290920160200192915050565b600081518084526020808501945080840160005b83811015614b5d5781516001600160401b031687529582019590820190600101614b38565b509495945050505050565b6001600160401b0381511682526000602082015160406020850152614b906040850182614af8565b949350505050565b600081518084526020808501945080840160005b83811015614b5d57815163ffffffff1687529582019590820190600101614bac565b600081518084526020808501808196508360051b8101915082860160005b85811015614c3c578284038952815160408151818752614c0e82880182614af8565b91505086820151915085810387870152614c288183614b68565b9a87019a9550505090840190600101614bec565b5091979650505050505050565b6000815160e08452614c5e60e0850182614af8565b905060208301518482036020860152614c778282614b24565b91505060408301518482036040860152614c918282614b68565b91505060608301518482036060860152614cab8282614af8565b91505060808301518482036080860152614cc58282614b98565b91505060a083015184820360a0860152614cdf8282614bce565b91505060c083015184820360c0860152610af28282614af8565b60038110614d0957614d09614a9a565b50565b60008151614d1981614cf9565b80845250602082015160606020850152614d366060850182614b68565b905060408301518482036040860152610af28282614af8565b6000815160a08452614d6460a0850182614af8565b905060208301518482036020860152614d7d8282614af8565b91505060408301518482036040860152614d978282614af8565b915050606083015163ffffffff808216606087015280608086015116608087015250508091505092915050565b6000815160608452614dd96060850182614af8565b905063ffffffff60208401511660208501526001600160401b0360408401511660408501528091505092915050565b6000815160608452614e1d6060850182614af8565b905063ffffffff602084015116602085015260408301518482036040860152610af28282614b68565b60028110614ac057614ac0614a9a565b614ac081614cf9565b602081526000825160e06020840152614e7d61010084018251614ab0565b6020810151610120614e99818601836001600160401b03169052565b60408301519150610140614eb48187018463ffffffff169052565b60608401519250610160614eca81880185614ac4565b6080850151935061020061018081818a0152614eea6103008a0187614c49565b955060a08701516101a0614f01818c018315159052565b60c0890151915060ff196101c0818d8b0301818e0152614f218a85614d0c565b995060e08b015193506101e0614f3a818f018615159052565b6101008c01519450828e8c0301878f0152614f558b86614d4f565b998c0151999a50614f6b6102208f018b15159052565b888c01519950614f806102408f018b15159052565b878c01519950614f956102608f018b15159052565b858c01519950614faa6102808f018b15159052565b838c01519950828e8c03016102a08f0152614fc58b8b614dc4565b9a50818c01519950614fdc6102c08f018b15159052565b808c01519b505050808c8a03016102e08d015250505050505050506150018183614e08565b9150506020840151601f19808584030160408601526150208383614af8565b9250604086015191506150366060860183614e46565b60608601519150808584030160808601526150518383614af8565b92506080860151915061506760a0860183614e56565b60a08601519150808584030160c08601526150828383614af8565b925060c08601519150808584030160e086015250610af28282614af8565b6040815260006150b36040830185614af8565b905063ffffffff831660208301529392505050565b6000602082840312156150da57600080fd5b81516001600160401b038111156150f057600080fd5b8201601f8101841361510157600080fd5b805161510f614a62826149f4565b81815285602083850101111561512457600080fd5b610af2826020830160208601614ad4565b80516020808301519190811015615156576000198160200360031b1b821691505b50919050565b8481528360208201528260408201526080606082015260006151816080830184614af8565b9695505050505050565b60006020828403121561519d57600080fd5b815180151581146151ad57600080fd5b9392505050565b6001600160401b0383168152604060208201526000614b906040830184614af8565b6000604082840312156151e857600080fd5b604051604081018181106001600160401b038211171561520a5761520a6149ae565b60405282516003811061521c57600080fd5b8152602083015163ffffffff8116811461523557600080fd5b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b0381811683821601908082111561527757615277615241565b5092915050565b6001600160401b0382811682821603908082111561527757615277615241565b600084516152b0818460208901614ad4565b8451908301906152c4818360208901614ad4565b84519101906152d7818360208801614ad4565b0195945050505050565b60008a516152f3818460208f01614ad4565b8a516153058183860160208f01614ad4565b8a51918401019061531a818360208e01614ad4565b895161532c8183850160208e01614ad4565b8951929091010190615342818360208c01614ad4565b87516153548183850160208c01614ad4565b875192909101019061536a818360208a01614ad4565b855161537c8183850160208a01614ad4565b8551929091010190615392818360208801614ad4565b019b9a5050505050505050505050565b634e487b7160e01b600052603260045260246000fd5b6001600160401b038181168382160280821691908281146153db576153db615241565b505092915050565b60006001600160401b038083168181036153ff576153ff615241565b6001019392505050565b60008751602061541c8285838d01614ad4565b88519184019161542f8184848d01614ad4565b88519201916154418184848c01614ad4565b87519201916154538184848b01614ad4565b86519201916154658184848a01614ad4565b85519201916154778184848901614ad4565b919091019998505050505050505050565b6000865161549a818460208b01614ad4565b8651908301906154ae818360208b01614ad4565b86519101906154c1818360208a01614ad4565b85519101906154d4818360208901614ad4565b84519101906154e7818360208801614ad4565b0197965050505050505056fea26469706673582212204cb1bddfd4e08baedc3556521923f5dd4dff2d8852ddacbeb2aa1d8298f468e164736f6c63430008150033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063277e661d14610030575b600080fd5b61004361003e366004614a1b565b610059565b6040516100509190614e5f565b60405180910390f35b61006161478a565b60008061007160008586516103c0565b92505091508161009457604051636eca2e4b60e01b815260040160405180910390fd5b60006100a38260000151610551565b905060007333937f3b8a9107e409931b70478ae716cb51aee863227bb04d8360146040518363ffffffff1660e01b81526004016100e19291906150a0565b600060405180830381865af41580156100fe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261012691908101906150c8565b905082602001518051906020012081805190602001201461015a57604051638b56642d60e01b815260040160405180910390fd5b505060608101516020810151604082015160a08401519192909160009073fa7321696663ea6b9c8d4d3c892c1176e2587a3990632bf6eda89061019c90615135565b868689602001516040518563ffffffff1660e01b81526004016101c2949392919061515c565b602060405180830381865af41580156101df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610203919061518b565b90508061022357604051638baa579f60e01b815260040160405180910390fd5b505082516020015160a084015160405163561a662d60e11b8152600094506ffc1237824fb747abde0ff18990e59b7e935063ac34cc5a926102689290916004016151b4565b6040805180830381865afa158015610284573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a891906151d6565b90506001815160028111156102bf576102bf614a9a565b146102dd57604051630eda9c3d60e31b815260040160405180910390fd5b6001826080015160028111156102f5576102f5614a9a565b1461031357604051632171ecf960e01b815260040160405180910390fd5b600d825151600d81111561032957610329614a9a565b1461034757604051635b60892f60e01b815260040160405180910390fd5b81516101e00151515161010010156103725760405163e7bc872f60e01b815260040160405180910390fd5b81516101e0015160200151600163ffffffff82161080610398575060048163ffffffff16115b156103b657604051639a759aa960e01b815260040160405180910390fd5b5090949350505050565b6000806103cb61478a565b6103d361478a565b6000876001600160401b0381166103ea8883615257565b6001600160401b03161015610409576000955093509091506105489050565b6001600160401b03871661041d8a8361527e565b6001600160401b0316101561050b57600080600061043b848c61080f565b91965091945090925090508261045f57506000975091955092935061054892505050565b6007826001600160401b0316111561048557506000975091955092935061054892505050565b846001600160401b0316826001600160401b0316116104b257506000975091955092935061054892505050565b6104bc8282610901565b9250826104d757506000975091955092935061054892505050565b6104e4848c8c858a6109cb565b945092508261050157506000975091955092935061054892505050565b5092506104099050565b610515878a615257565b6001600160401b0316816001600160401b03161461053d576000955093509091506105489050565b600195509350909150505b93509350939050565b606060008260000151600d81111561056b5761056b614a9a565b6001600160401b031660000361058f5760408051600081526020810190915261059b565b61059b60016000610ad3565b905060008360000151600d8111156105b5576105b5614a9a565b6001600160401b03166000036105d9576040805160008152602081019091526105f5565b83516105f590600d8111156105f0576105f0614a9a565b610afb565b9050600084602001516001600160401b03166000036106225760408051600081526020810190915261062e565b61062e60026000610ad3565b9050600085602001516001600160401b031660000361065b57604080516000815260208101909152610668565b6106688660200151610b09565b90506000866040015163ffffffff166001600160401b031660000361069b576040805160008152602081019091526106a7565b6106a760036000610ad3565b90506000876040015163ffffffff166001600160401b03166000036106da576040805160008152602081019091526106e7565b6106e78860400151610b14565b905060008860600151600381111561070157610701614a9a565b6001600160401b031660000361072557604080516000815260208101909152610731565b61073160046000610ad3565b905060008960600151600381111561074b5761074b614a9a565b6001600160401b031660000361076f57604080516000815260208101909152610788565b6107888a6060015160038111156105f0576105f0614a9a565b9050600061079c60108c6101e00151610b25565b805160208083015160408085015190519495506000946107bd94930161529e565b60405160208183030381529060405290508989898989898989886040516020016107ef999897969594939291906152e1565b6040516020818303038152906040529a5050505050505050505050919050565b60008060008060008060006108248989610bdd565b925092509250826108445750600095509350849250600691506108f89050565b600381901c671fffffffffffffff1660078216600681106108785760008460006006985098509850985050505050506108f8565b6000816001600160401b0316600681111561089557610895614a9a565b905060038160068111156108ab576108ab614a9a565b14806108c8575060048160068111156108c6576108c6614a9a565b145b156108e7576000856000600699509950995099505050505050506108f8565b600199509397509095509193505050505b92959194509250565b6000826001600160401b03166001036109315760025b82600681111561092957610929614a9a565b1490506109c5565b826001600160401b0316600203610949576002610917565b826001600160401b0316600303610961576000610917565b826001600160401b0316600403610979576002610917565b826001600160401b0316600503610991576000610917565b826001600160401b03166006036109a9576002610917565b826001600160401b03166007036109c1576002610917565b5060005b92915050565b600080866001600160401b038516600103610a0e5760006109ed828987610d88565b9250905080610a025750600092509050610ac9565b50600192509050610ac9565b846001600160401b0316600203610a2c5760006109ed828987610e15565b846001600160401b0316600303610a4a5760006109ed828987610f5e565b846001600160401b0316600403610a685760006109ed828987611017565b846001600160401b0316600503610a865760006109ed828987611146565b846001600160401b0316600603610aa45760006109ed8289876111f0565b846001600160401b0316600703610ac25760006109ed82898761131f565b6000925090505b9550959350505050565b60606807fffffffffffffff8600384901b1682176000610af28261144e565b95945050505050565b60606109c58260030b61144e565b60606109c58261144e565b60606109c58263ffffffff1661144e565b610b4960405180606001604052806060815260200160608152602001606081525090565b6000610b54836115a8565b805190915060006001600160401b038216610b7d57604080516000815260208101909152610b88565b610b88866002610ad3565b9050600080836001600160401b031611610bb057604080516000815260208101909152610bb9565b610bb983610b09565b60408051606081018252938452602084019190915282019390935295945050505050565b60008060008060005b600a6001600160401b0382161015610cd3578551610c048883615257565b6001600160401b031610610c245760008760009450945094505050610d81565b600086610c31838a615257565b6001600160401b031681518110610c4a57610c4a6153a2565b016020015160f81c9050607f8116610c638360076153b8565b60ff82166001600160401b03919091161b939093179260808216600003610cbe576000836001600160401b0316118015610c9e575060ff8116155b15610cb757600089600096509650965050505050610d81565b5050610cd3565b50508080610ccb906153e3565b915050610be6565b600a6001600160401b03821610610cf65760008760009450945094505050610d81565b610d026001600a61527e565b6001600160401b0316816001600160401b031603610d6057600186610d27838a615257565b6001600160401b031681518110610d4057610d406153a2565b016020015160f81c1115610d605760008760009450945094505050610d81565b6001610d6c8289615257565b610d77906001615257565b8394509450945050505b9250925092565b600080600080610d98878761172b565b909850909250905081610db357600087935093505050610e0d565b806001600160401b0316600003610dd257600087935093505050610e0d565b610dda6147cd565b610de5888884611747565b909950909350905082610e015760008894509450505050610e0d565b85525060019250859150505b935093915050565b600080600080610e25878761172b565b909850909250905081610e4057600087935093505050610e0d565b806001600160401b0316600003610e5f57600087935093505050610e0d565b806001600160401b03166001600160401b03811115610e8057610e806149ae565b6040519080825280601f01601f191660200182016040528015610eaa576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b03161015610f445786610ed8828a615257565b6001600160401b031681518110610ef157610ef16153a2565b602001015160f81c60f81b8660200151826001600160401b031681518110610f1b57610f1b6153a2565b60200101906001600160f81b031916908160001a90535080610f3c816153e3565b915050610eb3565b50610f4f8188615257565b60019890975095505050505050565b600080600080610f6e8787611892565b909850909250905081610f8957600087935093505050610e0d565b8060030b600003610fa257600087935093505050610e0d565b60008160030b1280610fb7575060018160030b135b15610fca57600087935093505050610e0d565b8060030b6001811115610fdf57610fdf614a9a565b85604001906001811115610ff557610ff5614a9a565b9081600181111561100857611008614a9a565b90525060019795505050505050565b600080600080611027878761172b565b90985090925090508161104257600087935093505050610e0d565b806001600160401b031660000361106157600087935093505050610e0d565b806001600160401b03166001600160401b03811115611082576110826149ae565b6040519080825280601f01601f1916602001820160405280156110ac576020820181803683370190505b50606086015260005b816001600160401b0316816001600160401b03161015610f4457866110da828a615257565b6001600160401b0316815181106110f3576110f36153a2565b602001015160f81c60f81b8660600151826001600160401b03168151811061111d5761111d6153a2565b60200101906001600160f81b031916908160001a9053508061113e816153e3565b9150506110b5565b6000806000806111568787611892565b90985090925090508161117157600087935093505050610e0d565b8060030b60000361118a57600087935093505050610e0d565b60008160030b128061119f575060028160030b135b156111b257600087935093505050610e0d565b8060030b60028111156111c7576111c7614a9a565b856080019060028111156111dd576111dd614a9a565b9081600281111561100857611008614a9a565b600080600080611200878761172b565b90985090925090508161121b57600087935093505050610e0d565b806001600160401b031660000361123a57600087935093505050610e0d565b806001600160401b03166001600160401b0381111561125b5761125b6149ae565b6040519080825280601f01601f191660200182016040528015611285576020820181803683370190505b5060a086015260005b816001600160401b0316816001600160401b03161015610f4457866112b3828a615257565b6001600160401b0316815181106112cc576112cc6153a2565b602001015160f81c60f81b8660a00151826001600160401b0316815181106112f6576112f66153a2565b60200101906001600160f81b031916908160001a90535080611317816153e3565b91505061128e565b60008060008061132f878761172b565b90985090925090508161134a57600087935093505050610e0d565b806001600160401b031660000361136957600087935093505050610e0d565b806001600160401b03166001600160401b0381111561138a5761138a6149ae565b6040519080825280601f01601f1916602001820160405280156113b4576020820181803683370190505b5060c086015260005b816001600160401b0316816001600160401b03161015610f4457866113e2828a615257565b6001600160401b0316815181106113fb576113fb6153a2565b602001015160f81c60f81b8660c00151826001600160401b031681518110611425576114256153a2565b60200101906001600160f81b031916908160001a90535080611446816153e3565b9150506113bd565b60608160015b607f826001600160401b0316111561148a576007826001600160401b0316901c91506001816114839190615257565b9050611454565b6000816001600160401b03166001600160401b038111156114ad576114ad6149ae565b6040519080825280601f01601f1916602001820160405280156114d7576020820181803683370190505b50905084925060005b826001600160401b0316816001600160401b031610156115595783607f1660801760f81b82826001600160401b03168151811061151f5761151f6153a2565b60200101906001600160f81b031916908160001a9053506007846001600160401b0316901c93508080611551906153e3565b9150506114e0565b50607f60f81b8161156b60018561527e565b6001600160401b031681518110611584576115846153a2565b0160200180519091166001600160f81b03191690600082901a905350949350505050565b6060600080836000015151116115cc576040805160008152602081019091526115d8565b6115d860016002610ad3565b9050600080846000015151116115fc57604080516000815260208101909152611608565b83515161160890610b09565b90506000808560000151511161162c5760408051600081526020810190915261162f565b84515b90506000856020015163ffffffff166001600160401b03166000036116625760408051600081526020810190915261166e565b61166e60026000610ad3565b90506000866020015163ffffffff166001600160401b03166000036116a1576040805160008152602081019091526116ae565b6116ae8760200151610b14565b905060006116c1600389604001516118a1565b805160208083015160408085015190519495506000946116e294930161529e565b604051602081830303815290604052905086868686868560405160200161170e96959493929190615409565b604051602081830303815290604052975050505050505050919050565b600080600061173a85856118d0565b9250925092509250925092565b6000806117526147cd565b61175a6147cd565b6000876001600160401b0381166117718883615257565b6001600160401b03161015611790576000955093509091506105489050565b6001600160401b0387166117a48a8361527e565b6001600160401b0316101561050b5760008060006117c2848c61080f565b9196509194509092509050826117e657506000975091955092935061054892505050565b6010826001600160401b0316111561180c57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161183957506000975091955092935061054892505050565b6118438282611967565b92508261185e57506000975091955092935061054892505050565b61186b848c8c858a611ae9565b945092508261188857506000975091955092935061054892505050565b5092506117909050565b600080600061173a8585611ccd565b6118c560405180606001604052806060815260200160608152602001606081525090565b6000610b5483611d2c565b6000806000806000806118e38888610bdd565b925092509250826118ff5750600094509250839150610d819050565b816001600160401b03168183016001600160401b0316101561192c5750600094509250839150610d819050565b86516119388383615257565b6001600160401b031611156119585750600094509250839150610d819050565b60019891975095509350505050565b6000826001600160401b0316600103611981576000610917565b826001600160401b0316600203611999576000610917565b826001600160401b03166003036119b1576000610917565b826001600160401b03166004036119c9576000610917565b826001600160401b03166005036119e1576002610917565b826001600160401b03166006036119f9576000610917565b826001600160401b0316600703611a11576002610917565b826001600160401b0316600803611a29576000610917565b826001600160401b0316600903611a41576002610917565b826001600160401b0316600a03611a59576000610917565b826001600160401b0316600b03611a71576000610917565b826001600160401b0316600c03611a89576000610917565b826001600160401b0316600d03611aa1576000610917565b826001600160401b0316600e03611ab9576002610917565b826001600160401b0316600f03611ad1576000610917565b826001600160401b03166010036109c1576002610917565b600080866001600160401b038516600103611b0b5760006109ed828987611e5e565b846001600160401b0316600203611b295760006109ed828987611f05565b846001600160401b0316600303611b475760006109ed828987611f6c565b846001600160401b0316600403611b655760006109ed828987611fcd565b846001600160401b0316600503611b835760006109ed828987612077565b846001600160401b0316600603611ba15760006109ed828987612105565b846001600160401b0316600703611bbf5760006109ed82898761215e565b846001600160401b0316600803611bdd5760006109ed8289876121ec565b846001600160401b0316600903611bfb5760006109ed828987612245565b846001600160401b0316600a03611c195760006109ed8289876122d4565b846001600160401b0316600b03611c375760006109ed82898761232e565b846001600160401b0316600c03611c555760006109ed828987612388565b846001600160401b0316600d03611c735760006109ed8289876123e2565b846001600160401b0316600e03611c915760006109ed82898761243c565b846001600160401b0316600f03611caf5760006109ed8289876124e0565b846001600160401b0316601003610ac25760006109ed82898761253a565b600080600080600080611ce08888610bdd565b92509250925082611cfc5750600094509250839150610d819050565b6001603f82901c166000036119585767ffffffff000000008116156119585750600094509250839150610d819050565b6060600082600001516001600160401b0316600003611d5957604080516000815260208101909152611d65565b611d6560016000610ad3565b9050600083600001516001600160401b0316600003611d9257604080516000815260208101909152611d9d565b8351611d9d90610b09565b905060008085602001515111611dc157604080516000815260208101909152611dcc565b611dcc600280610ad3565b905060008086602001515111611df057604080516000815260208101909152611dfe565b611dfe866020015151610b09565b905060008087602001515111611e2257604080516000815260208101909152611e28565b86602001515b90508484848484604051602001611e43959493929190615488565b60405160208183030381529060405295505050505050919050565b600080600080611e6e8787611892565b909850909250905081611e8957600087935093505050610e0d565b8060030b600003611ea257600087935093505050610e0d565b60008160030b1280611eb75750600d8160030b135b15611eca57600087935093505050610e0d565b8060030b600d811115611edf57611edf614a9a565b8590600d811115611ef257611ef2614a9a565b9081600d81111561100857611008614a9a565b600080600080611f1587876125c9565b909850909250905081611f3057600087935093505050610e0d565b806001600160401b0316600003611f4f57600087935093505050610e0d565b6001600160401b0316602094909401939093525060019492505050565b600080600080611f7c87876125f8565b909850909250905081611f9757600087935093505050610e0d565b8063ffffffff16600003611fb357600087935093505050610e0d565b63ffffffff16604094909401939093525060019492505050565b600080600080611fdd8787611892565b909850909250905081611ff857600087935093505050610e0d565b8060030b60000361201157600087935093505050610e0d565b60008160030b1280612026575060038160030b135b1561203957600087935093505050610e0d565b8060030b600381111561204e5761204e614a9a565b8560600190600381111561206457612064614a9a565b9081600381111561100857611008614a9a565b600080600080612087878761172b565b9098509092509050816120a257600087935093505050610e0d565b806001600160401b03166000036120c157600087935093505050610e0d565b6120c9614883565b6120d4888884612648565b9099509093509050826120f05760008894509450505050610e0d565b60809590950194909452506001959350505050565b6000806000806121158787612793565b90985090925090508161213057600087935093505050610e0d565b80151560000361214857600087935093505050610e0d565b151560a094909401939093525060019492505050565b60008060008061216e878761172b565b90985090925090508161218957600087935093505050610e0d565b806001600160401b03166000036121a857600087935093505050610e0d565b6121b06148d9565b6121bb888884612819565b9099509093509050826121d75760008894509450505050610e0d565b60c09590950194909452506001959350505050565b6000806000806121fc8787612793565b90985090925090508161221757600087935093505050610e0d565b80151560000361222f57600087935093505050610e0d565b151560e094909401939093525060019492505050565b600080600080612255878761172b565b90985090925090508161227057600087935093505050610e0d565b806001600160401b031660000361228f57600087935093505050610e0d565b612297614914565b6122a2888884612964565b9099509093509050826122be5760008894509450505050610e0d565b6101009590950194909452506001959350505050565b6000806000806122e48787612793565b9098509092509050816122ff57600087935093505050610e0d565b80151560000361231757600087935093505050610e0d565b151561012094909401939093525060019492505050565b60008060008061233e8787612793565b90985090925090508161235957600087935093505050610e0d565b80151560000361237157600087935093505050610e0d565b151561014094909401939093525060019492505050565b6000806000806123988787612793565b9098509092509050816123b357600087935093505050610e0d565b8015156000036123cb57600087935093505050610e0d565b151561016094909401939093525060019492505050565b6000806000806123f28787612793565b90985090925090508161240d57600087935093505050610e0d565b80151560000361242557600087935093505050610e0d565b151561018094909401939093525060019492505050565b60008060008061244c878761172b565b90985090925090508161246757600087935093505050610e0d565b806001600160401b031660000361248657600087935093505050610e0d565b60408051606080820183528152600060208201819052918101919091526124ae888884612aaf565b9099509093509050826124ca5760008894509450505050610e0d565b6101a09590950194909452506001959350505050565b6000806000806124f08787612793565b90985090925090508161250b57600087935093505050610e0d565b80151560000361252357600087935093505050610e0d565b15156101c094909401939093525060019492505050565b60008060008061254a878761172b565b90985090925090508161256557600087935093505050610e0d565b806001600160401b031660000361258457600087935093505050610e0d565b61258c61494f565b612597888884612c1c565b9099509093509050826125b35760008894509450505050610e0d565b6101e09590950194909452506001959350505050565b6000806000806000806125dc8888610bdd565b925092509250826119585750600094509250839150610d819050565b60008060008060008061260b8888610bdd565b925092509250826126275750600094509250839150610d819050565b67ffffffff000000008116156119585750600094509250839150610d819050565b600080612653614883565b61265b614883565b6000876001600160401b0381166126728883615257565b6001600160401b03161015612691576000955093509091506105489050565b6001600160401b0387166126a58a8361527e565b6001600160401b0316101561050b5760008060006126c3848c61080f565b9196509194509092509050826126e757506000975091955092935061054892505050565b6007826001600160401b0316111561270d57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161273a57506000975091955092935061054892505050565b6127448282612d67565b92508261275f57506000975091955092935061054892505050565b61276c848c8c858a612de1565b945092508261278957506000975091955092935061054892505050565b5092506126919050565b6000806000806000806127a68888610bdd565b925092509250826127c25750600094509250839150610d819050565b6001816001600160401b031611156127e55750600094509250839150610d819050565b806001600160401b0316600003612808575060019450925060009150610d819050565b506001979096508795509350505050565b6000806128246148d9565b61282c6148d9565b6000876001600160401b0381166128438883615257565b6001600160401b03161015612862576000955093509091506105489050565b6001600160401b0387166128768a8361527e565b6001600160401b0316101561050b576000806000612894848c61080f565b9196509194509092509050826128b857506000975091955092935061054892505050565b6003826001600160401b031611156128de57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161290b57506000975091955092935061054892505050565b6129158282612eb7565b92508261293057506000975091955092935061054892505050565b61293d848c8c858a612f01565b945092508261295a57506000975091955092935061054892505050565b5092506128629050565b60008061296f614914565b612977614914565b6000876001600160401b03811661298e8883615257565b6001600160401b031610156129ad576000955093509091506105489050565b6001600160401b0387166129c18a8361527e565b6001600160401b0316101561050b5760008060006129df848c61080f565b919650919450909250905082612a0357506000975091955092935061054892505050565b6005826001600160401b03161115612a2957506000975091955092935061054892505050565b846001600160401b0316826001600160401b031611612a5657506000975091955092935061054892505050565b612a608282612f5f565b925082612a7b57506000975091955092935061054892505050565b612a88848c8c858a612fd9565b9450925082612aa557506000975091955092935061054892505050565b5092506129ad9050565b60408051606080820183528082526000602080840182905283850182905284518084018652928352820181905292810183905282919082876001600160401b038116612afb8883615257565b6001600160401b03161015612b1a576000955093509091506105489050565b6001600160401b038716612b2e8a8361527e565b6001600160401b0316101561050b576000806000612b4c848c61080f565b919650919450909250905082612b7057506000975091955092935061054892505050565b6003826001600160401b03161115612b9657506000975091955092935061054892505050565b846001600160401b0316826001600160401b031611612bc357506000975091955092935061054892505050565b612bcd8282613073565b925082612be857506000975091955092935061054892505050565b612bf5848c8c858a6130bd565b9450925082612c1257506000975091955092935061054892505050565b509250612b1a9050565b600080612c2761494f565b612c2f61494f565b6000876001600160401b038116612c468883615257565b6001600160401b03161015612c65576000955093509091506105489050565b6001600160401b038716612c798a8361527e565b6001600160401b0316101561050b576000806000612c97848c61080f565b919650919450909250905082612cbb57506000975091955092935061054892505050565b6003826001600160401b03161115612ce157506000975091955092935061054892505050565b846001600160401b0316826001600160401b031611612d0e57506000975091955092935061054892505050565b612d18828261311b565b925082612d3357506000975091955092935061054892505050565b612d40848c8c858a61314d565b9450925082612d5d57506000975091955092935061054892505050565b509250612c659050565b6000826001600160401b0316600103612d81576002610917565b826001600160401b0316600203612d99576002610917565b826001600160401b0316600303612db1576002610917565b826001600160401b0316600403612dc9576002610917565b826001600160401b0316600503610991576002610917565b600080866001600160401b038516600103612e035760006109ed8289876131ab565b846001600160401b0316600203612e215760006109ed8289876131fb565b846001600160401b0316600303612e3f5760006109ed828987613404565b846001600160401b0316600403612e5d5760006109ed82898761349f565b846001600160401b0316600503612e7b5760006109ed8289876134f6565b846001600160401b0316600603612e995760006109ed8289876136bb565b846001600160401b0316600703610ac25760006109ed82898761391e565b6000826001600160401b0316600103612ed1576000610917565b826001600160401b0316600203612ee9576002610917565b826001600160401b03166003036109c1576002610917565b600080866001600160401b038516600103612f235760006109ed828987613975565b846001600160401b0316600203612f415760006109ed828987613a09565b846001600160401b0316600303610ac25760006109ed828987613aa4565b6000826001600160401b0316600103612f79576002610917565b826001600160401b0316600203612f91576002610917565b826001600160401b0316600303612fa9576002610917565b826001600160401b0316600403612fc1576000610917565b826001600160401b03166005036109c1576000610917565b600080866001600160401b038516600103612ffb5760006109ed828987613afb565b846001600160401b03166002036130195760006109ed828987613c27565b846001600160401b03166003036130375760006109ed828987613d56565b846001600160401b03166004036130555760006109ed828987613e85565b846001600160401b0316600503610ac25760006109ed828987613ee6565b6000826001600160401b031660010361308d576002610917565b826001600160401b03166002036130a5576000610917565b826001600160401b03166003036109c1576000610917565b600080866001600160401b0385166001036130df5760006109ed8289876131ab565b846001600160401b03166002036130fd5760006109ed828987613f47565b846001600160401b0316600303610ac25760006109ed828987613fa8565b6000826001600160401b0316600103613135576002610917565b826001600160401b0316600203612ee9576000610917565b600080866001600160401b03851660010361316f5760006109ed82898761400f565b846001600160401b031660020361318d5760006109ed828987613f47565b846001600160401b0316600303610ac25760006109ed828987613404565b600080600060606131bc878761413b565b9098509092509050816131d757600087935093505050610e0d565b80516000036131ee57600087935093505050610e0d565b9093525060019492505050565b60008060008061320b87876118d0565b90985090925090508161322657600087935093505050610e0d565b806001600160401b031660000361324557600087935093505050610e0d565b866001600160401b03811661325a8383615257565b6001600160401b031610156132785760008894509450505050610e0d565b60005b6001600160401b03831661328f838b61527e565b6001600160401b031610156132db5760006132aa8a8a6125c9565b909b509095509050846132c85760008a965096505050505050610e0d565b6132d3600183615257565b91505061327b565b806001600160401b03166001600160401b038111156132fc576132fc6149ae565b604051908082528060200260200182016040528015613325578160200160208202803683370190505b506020880152909750879060005b816001600160401b0316816001600160401b031610156133c35760006133598b8b6125c9565b909c509096509050856133785760008b97509750505050505050610e0d565b808960200151836001600160401b031681518110613398576133986153a2565b6001600160401b039092166020928302919091019091015250806133bb816153e3565b915050613333565b506133ce8383615257565b6001600160401b0316896001600160401b0316146133f6576000899550955050505050610e0d565b506001989650505050505050565b600080600080613414878761172b565b90985090925090508161342f57600087935093505050610e0d565b806001600160401b031660000361344e57600087935093505050610e0d565b60408051808201909152600081526060602082015261346e888884614279565b90995090935090508261348a5760008894509450505050610e0d565b60409590950194909452506001959350505050565b600080600060606134b0878761413b565b9098509092509050816134cb57600087935093505050610e0d565b80516000036134e257600087935093505050610e0d565b606094909401939093525060019492505050565b60008060008061350687876118d0565b90985090925090508161352157600087935093505050610e0d565b806001600160401b031660000361354057600087935093505050610e0d565b866001600160401b0381166135558383615257565b6001600160401b031610156135735760008894509450505050610e0d565b60005b6001600160401b03831661358a838b61527e565b6001600160401b031610156135d65760006135a58a8a6125f8565b909b509095509050846135c35760008a965096505050505050610e0d565b6135ce600183615257565b915050613576565b806001600160401b03166001600160401b038111156135f7576135f76149ae565b604051908082528060200260200182016040528015613620578160200160208202803683370190505b506080880152909750879060005b816001600160401b0316816001600160401b031610156133c35760006136548b8b6125f8565b909c509096509050856136735760008b97509750505050505050610e0d565b808960800151836001600160401b031681518110613693576136936153a2565b63ffffffff9092166020928302919091019091015250806136b3816153e3565b91505061362e565b6000808085815b8651886001600160401b031610156137b05760006136e0898961172b565b909a509094509050836136fd576000899550955050505050610e0d565b6001600160401b038916613711828b615257565b6001600160401b03161015613730576000899550955050505050610e0d565b61373a818a615257565b9850613747600183615257565b91508751896001600160401b03161061376057506137b0565b60008061376d8b8b61080f565b919d5091975090925090508561378f5760008b97509750505050505050610e0d565b816001600160401b03166006146137a8575050506137b0565b5050506136c2565b806001600160401b03166001600160401b038111156137d1576137d16149ae565b60405190808252806020026020018201604052801561380a57816020015b6137f7614981565b8152602001906001900390816137ef5790505b5060a0870152909650869060005b816001600160401b0316816001600160401b031610156133f657600061383e8a8a61172b565b909b5090955090508461385c5760008a965096505050505050610e0d565b899350613867614981565b6138728b8b846143e4565b909c509096509050856138915760008b97509750505050505050610e0d565b808960a00151846001600160401b0316815181106138b1576138b16153a2565b60209081029190910101526138c760018561527e565b6001600160401b0316836001600160401b03161015613909576138ea8b8b6125c9565b909c509096509150856139095760008b97509750505050505050610e0d565b50508080613916906153e3565b915050613818565b6000806000606061392f878761413b565b90985090925090508161394a57600087935093505050610e0d565b805160000361396157600087935093505050610e0d565b60c094909401939093525060019492505050565b6000806000806139858787611892565b9098509092509050816139a057600087935093505050610e0d565b8060030b6000036139b957600087935093505050610e0d565b60008160030b12806139ce575060028160030b135b156139e157600087935093505050610e0d565b8060030b60028111156139f6576139f6614a9a565b859060028111156111dd576111dd614a9a565b600080600080613a19878761172b565b909850909250905081613a3457600087935093505050610e0d565b806001600160401b0316600003613a5357600087935093505050610e0d565b604080518082019091526000815260606020820152613a73888884614279565b909950909350905082613a8f5760008894509450505050610e0d565b60209590950194909452506001959350505050565b60008060006060613ab5878761413b565b909850909250905081613ad057600087935093505050610e0d565b8051600003613ae757600087935093505050610e0d565b604094909401939093525060019492505050565b600080600080613b0b878761172b565b909850909250905081613b2657600087935093505050610e0d565b806001600160401b0316600003613b4557600087935093505050610e0d565b806001600160401b03166001600160401b03811115613b6657613b666149ae565b6040519080825280601f01601f191660200182016040528015613b90576020820181803683370190505b50855260005b816001600160401b0316816001600160401b03161015610f445786613bbb828a615257565b6001600160401b031681518110613bd457613bd46153a2565b602001015160f81c60f81b8660000151826001600160401b031681518110613bfe57613bfe6153a2565b60200101906001600160f81b031916908160001a90535080613c1f816153e3565b915050613b96565b600080600080613c37878761172b565b909850909250905081613c5257600087935093505050610e0d565b806001600160401b0316600003613c7157600087935093505050610e0d565b806001600160401b03166001600160401b03811115613c9257613c926149ae565b6040519080825280601f01601f191660200182016040528015613cbc576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b03161015610f445786613cea828a615257565b6001600160401b031681518110613d0357613d036153a2565b602001015160f81c60f81b8660200151826001600160401b031681518110613d2d57613d2d6153a2565b60200101906001600160f81b031916908160001a90535080613d4e816153e3565b915050613cc5565b600080600080613d66878761172b565b909850909250905081613d8157600087935093505050610e0d565b806001600160401b0316600003613da057600087935093505050610e0d565b806001600160401b03166001600160401b03811115613dc157613dc16149ae565b6040519080825280601f01601f191660200182016040528015613deb576020820181803683370190505b50604086015260005b816001600160401b0316816001600160401b03161015610f445786613e19828a615257565b6001600160401b031681518110613e3257613e326153a2565b602001015160f81c60f81b8660400151826001600160401b031681518110613e5c57613e5c6153a2565b60200101906001600160f81b031916908160001a90535080613e7d816153e3565b915050613df4565b600080600080613e9587876125f8565b909850909250905081613eb057600087935093505050610e0d565b8063ffffffff16600003613ecc57600087935093505050610e0d565b63ffffffff16606094909401939093525060019492505050565b600080600080613ef687876125f8565b909850909250905081613f1157600087935093505050610e0d565b8063ffffffff16600003613f2d57600087935093505050610e0d565b63ffffffff16608094909401939093525060019492505050565b600080600080613f5787876125f8565b909850909250905081613f7257600087935093505050610e0d565b8063ffffffff16600003613f8e57600087935093505050610e0d565b63ffffffff16602094909401939093525060019492505050565b600080600080613fb887876125c9565b909850909250905081613fd357600087935093505050610e0d565b806001600160401b0316600003613ff257600087935093505050610e0d565b6001600160401b0316604094909401939093525060019492505050565b60008060008061401f878761172b565b90985090925090508161403a57600087935093505050610e0d565b806001600160401b031660000361405957600087935093505050610e0d565b806001600160401b03166001600160401b0381111561407a5761407a6149ae565b6040519080825280601f01601f1916602001820160405280156140a4576020820181803683370190505b50855260005b816001600160401b0316816001600160401b03161015610f4457866140cf828a615257565b6001600160401b0316815181106140e8576140e86153a2565b602001015160f81c60f81b8660000151826001600160401b031681518110614112576141126153a2565b60200101906001600160f81b031916908160001a90535080614133816153e3565b9150506140aa565b6000806060600080600061414f88886118d0565b9250925092508261417b5760008260405180602001604052806000815250955095509550505050610d81565b6000816001600160401b03166001600160401b0381111561419e5761419e6149ae565b6040519080825280601f01601f1916602001820160405280156141c8576020820181803683370190505b50905060005b826001600160401b0316816001600160401b0316101561425b57886141f38286615257565b6001600160401b03168151811061420c5761420c6153a2565b602001015160f81c60f81b82826001600160401b031681518110614232576142326153a2565b60200101906001600160f81b031916908160001a90535080614253816153e3565b9150506141ce565b5060016142688385615257565b909750955093505050509250925092565b60008061429760408051808201909152600081526060602082015290565b6040805180820190915260008152606060208201526000876001600160401b0381166142c38883615257565b6001600160401b031610156142e2576000955093509091506105489050565b6001600160401b0387166142f68a8361527e565b6001600160401b0316101561050b576000806000614314848c61080f565b91965091945090925090508261433857506000975091955092935061054892505050565b6002826001600160401b0316111561435e57506000975091955092935061054892505050565b846001600160401b0316826001600160401b03161161438b57506000975091955092935061054892505050565b614395828261452f565b9250826143b057506000975091955092935061054892505050565b6143bd848c8c858a614561565b94509250826143da57506000975091955092935061054892505050565b5092506142e29050565b6000806143ef614981565b6143f7614981565b6000876001600160401b03811661440e8883615257565b6001600160401b0316101561442d576000955093509091506105489050565b6001600160401b0387166144418a8361527e565b6001600160401b0316101561050b57600080600061445f848c61080f565b91965091945090925090508261448357506000975091955092935061054892505050565b6002826001600160401b031611156144a957506000975091955092935061054892505050565b846001600160401b0316826001600160401b0316116144d657506000975091955092935061054892505050565b6144e082826145a1565b9250826144fb57506000975091955092935061054892505050565b614508848c8c858a6145bb565b945092508261452557506000975091955092935061054892505050565b50925061442d9050565b6000826001600160401b0316600103614549576000610917565b826001600160401b03166002036109c1576002610917565b600080866001600160401b0385166001036145835760006109ed8289876145fb565b846001600160401b0316600203610ac25760006109ed82898761465b565b6000826001600160401b0316600103614549576002610917565b600080866001600160401b0385166001036145dd5760006109ed8289876131ab565b846001600160401b0316600203610ac25760006109ed828987613a09565b60008060008061460b87876125c9565b90985090925090508161462657600087935093505050610e0d565b806001600160401b031660000361464557600087935093505050610e0d565b6001600160401b03169093525060019492505050565b60008060008061466b878761172b565b90985090925090508161468657600087935093505050610e0d565b806001600160401b03166000036146a557600087935093505050610e0d565b806001600160401b03166001600160401b038111156146c6576146c66149ae565b6040519080825280601f01601f1916602001820160405280156146f0576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b03161015610f44578661471e828a615257565b6001600160401b031681518110614737576147376153a2565b602001015160f81c60f81b8660200151826001600160401b031681518110614761576147616153a2565b60200101906001600160f81b031916908160001a90535080614782816153e3565b9150506146f9565b6040518060e0016040528061479d6147cd565b81526060602082015260400160008152606060208201526040016000815260200160608152602001606081525090565b60408051610200810182526000808252602082018190529181018290526060810191909152608081016147fe614883565b8152600060208201526040016148126148d9565b815260006020820152604001614826614914565b81526000602082018190526040820181905260608201819052608082015260a00161486a604080516060808201835281526000602082018190529181019190915290565b81526000602082015260400161487e61494f565b905290565b6040518060e0016040528060608152602001606081526020016148b760408051808201909152600081526060602082015290565b8152602001606081526020016060815260200160608152602001606081525090565b6040805160608101909152806000815260200161490760408051808201909152600081526060602082015290565b8152602001606081525090565b6040518060a00160405280606081526020016060815260200160608152602001600063ffffffff168152602001600063ffffffff1681525090565b604080516060808201835281526000602082015290810161487e60408051808201909152600081526060602082015290565b60405180604001604052806060815260200161487e60408051808201909152600081526060602082015290565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156149ec576149ec6149ae565b604052919050565b60006001600160401b03821115614a0d57614a0d6149ae565b50601f01601f191660200190565b600060208284031215614a2d57600080fd5b81356001600160401b03811115614a4357600080fd5b8201601f81018413614a5457600080fd5b8035614a67614a62826149f4565b6149c4565b818152856020838501011115614a7c57600080fd5b81602084016020830137600091810160200191909152949350505050565b634e487b7160e01b600052602160045260246000fd5b600e8110614ac057614ac0614a9a565b9052565b60048110614ac057614ac0614a9a565b60005b83811015614aef578181015183820152602001614ad7565b50506000910152565b60008151808452614b10816020860160208601614ad4565b601f01601f19169290920160200192915050565b600081518084526020808501945080840160005b83811015614b5d5781516001600160401b031687529582019590820190600101614b38565b509495945050505050565b6001600160401b0381511682526000602082015160406020850152614b906040850182614af8565b949350505050565b600081518084526020808501945080840160005b83811015614b5d57815163ffffffff1687529582019590820190600101614bac565b600081518084526020808501808196508360051b8101915082860160005b85811015614c3c578284038952815160408151818752614c0e82880182614af8565b91505086820151915085810387870152614c288183614b68565b9a87019a9550505090840190600101614bec565b5091979650505050505050565b6000815160e08452614c5e60e0850182614af8565b905060208301518482036020860152614c778282614b24565b91505060408301518482036040860152614c918282614b68565b91505060608301518482036060860152614cab8282614af8565b91505060808301518482036080860152614cc58282614b98565b91505060a083015184820360a0860152614cdf8282614bce565b91505060c083015184820360c0860152610af28282614af8565b60038110614d0957614d09614a9a565b50565b60008151614d1981614cf9565b80845250602082015160606020850152614d366060850182614b68565b905060408301518482036040860152610af28282614af8565b6000815160a08452614d6460a0850182614af8565b905060208301518482036020860152614d7d8282614af8565b91505060408301518482036040860152614d978282614af8565b915050606083015163ffffffff808216606087015280608086015116608087015250508091505092915050565b6000815160608452614dd96060850182614af8565b905063ffffffff60208401511660208501526001600160401b0360408401511660408501528091505092915050565b6000815160608452614e1d6060850182614af8565b905063ffffffff602084015116602085015260408301518482036040860152610af28282614b68565b60028110614ac057614ac0614a9a565b614ac081614cf9565b602081526000825160e06020840152614e7d61010084018251614ab0565b6020810151610120614e99818601836001600160401b03169052565b60408301519150610140614eb48187018463ffffffff169052565b60608401519250610160614eca81880185614ac4565b6080850151935061020061018081818a0152614eea6103008a0187614c49565b955060a08701516101a0614f01818c018315159052565b60c0890151915060ff196101c0818d8b0301818e0152614f218a85614d0c565b995060e08b015193506101e0614f3a818f018615159052565b6101008c01519450828e8c0301878f0152614f558b86614d4f565b998c0151999a50614f6b6102208f018b15159052565b888c01519950614f806102408f018b15159052565b878c01519950614f956102608f018b15159052565b858c01519950614faa6102808f018b15159052565b838c01519950828e8c03016102a08f0152614fc58b8b614dc4565b9a50818c01519950614fdc6102c08f018b15159052565b808c01519b505050808c8a03016102e08d015250505050505050506150018183614e08565b9150506020840151601f19808584030160408601526150208383614af8565b9250604086015191506150366060860183614e46565b60608601519150808584030160808601526150518383614af8565b92506080860151915061506760a0860183614e56565b60a08601519150808584030160c08601526150828383614af8565b925060c08601519150808584030160e086015250610af28282614af8565b6040815260006150b36040830185614af8565b905063ffffffff831660208301529392505050565b6000602082840312156150da57600080fd5b81516001600160401b038111156150f057600080fd5b8201601f8101841361510157600080fd5b805161510f614a62826149f4565b81815285602083850101111561512457600080fd5b610af2826020830160208601614ad4565b80516020808301519190811015615156576000198160200360031b1b821691505b50919050565b8481528360208201528260408201526080606082015260006151816080830184614af8565b9695505050505050565b60006020828403121561519d57600080fd5b815180151581146151ad57600080fd5b9392505050565b6001600160401b0383168152604060208201526000614b906040830184614af8565b6000604082840312156151e857600080fd5b604051604081018181106001600160401b038211171561520a5761520a6149ae565b60405282516003811061521c57600080fd5b8152602083015163ffffffff8116811461523557600080fd5b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b0381811683821601908082111561527757615277615241565b5092915050565b6001600160401b0382811682821603908082111561527757615277615241565b600084516152b0818460208901614ad4565b8451908301906152c4818360208901614ad4565b84519101906152d7818360208801614ad4565b0195945050505050565b60008a516152f3818460208f01614ad4565b8a516153058183860160208f01614ad4565b8a51918401019061531a818360208e01614ad4565b895161532c8183850160208e01614ad4565b8951929091010190615342818360208c01614ad4565b87516153548183850160208c01614ad4565b875192909101019061536a818360208a01614ad4565b855161537c8183850160208a01614ad4565b8551929091010190615392818360208801614ad4565b019b9a5050505050505050505050565b634e487b7160e01b600052603260045260246000fd5b6001600160401b038181168382160280821691908281146153db576153db615241565b505092915050565b60006001600160401b038083168181036153ff576153ff615241565b6001019392505050565b60008751602061541c8285838d01614ad4565b88519184019161542f8184848d01614ad4565b88519201916154418184848c01614ad4565b87519201916154538184848b01614ad4565b86519201916154658184848a01614ad4565b85519201916154778184848901614ad4565b919091019998505050505050505050565b6000865161549a818460208b01614ad4565b8651908301906154ae818360208b01614ad4565b86519101906154c1818360208a01614ad4565b85519101906154d4818360208901614ad4565b84519101906154e7818360208801614ad4565b0197965050505050505056fea26469706673582212204cb1bddfd4e08baedc3556521923f5dd4dff2d8852ddacbeb2aa1d8298f468e164736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.