github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/cannon/PreimageOracle.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 import { IPreimageOracle } from "./interfaces/IPreimageOracle.sol"; 5 import { ISemver } from "src/universal/ISemver.sol"; 6 import { PreimageKeyLib } from "./PreimageKeyLib.sol"; 7 import { LibKeccak } from "@lib-keccak/LibKeccak.sol"; 8 import "src/cannon/libraries/CannonErrors.sol"; 9 import "src/cannon/libraries/CannonTypes.sol"; 10 11 /// @title PreimageOracle 12 /// @notice A contract for storing permissioned pre-images. 13 /// @custom:attribution Solady <https://github.com/Vectorized/solady/blob/main/src/utils/MerkleProofLib.sol#L13-L43> 14 /// @custom:attribution Beacon Deposit Contract <0x00000000219ab540356cbb839cbe05303d7705fa> 15 contract PreimageOracle is IPreimageOracle, ISemver { 16 //////////////////////////////////////////////////////////////// 17 // Constants & Immutables // 18 //////////////////////////////////////////////////////////////// 19 20 /// @notice The duration of the large preimage proposal challenge period. 21 uint256 internal immutable CHALLENGE_PERIOD; 22 /// @notice The minimum size of a preimage that can be proposed in the large preimage path. 23 uint256 internal immutable MIN_LPP_SIZE_BYTES; 24 /// @notice The minimum bond size for large preimage proposals. 25 uint256 public constant MIN_BOND_SIZE = 0.25 ether; 26 /// @notice The depth of the keccak256 merkle tree. Supports up to 65,536 keccak blocks, or ~8.91MB preimages. 27 uint256 public constant KECCAK_TREE_DEPTH = 16; 28 /// @notice The maximum number of keccak blocks that can fit into the merkle tree. 29 uint256 public constant MAX_LEAF_COUNT = 2 ** KECCAK_TREE_DEPTH - 1; 30 31 /// @notice The semantic version of the Preimage Oracle contract. 32 /// @custom:semver 0.1.0 33 string public constant version = "0.1.0"; 34 35 //////////////////////////////////////////////////////////////// 36 // Authorized Preimage Parts // 37 //////////////////////////////////////////////////////////////// 38 39 /// @notice Mapping of pre-image keys to pre-image lengths. 40 mapping(bytes32 => uint256) public preimageLengths; 41 /// @notice Mapping of pre-image keys to pre-image offsets to pre-image parts. 42 mapping(bytes32 => mapping(uint256 => bytes32)) public preimageParts; 43 /// @notice Mapping of pre-image keys to pre-image part offsets to preimage preparedness. 44 mapping(bytes32 => mapping(uint256 => bool)) public preimagePartOk; 45 46 //////////////////////////////////////////////////////////////// 47 // Large Preimage Proposals // 48 //////////////////////////////////////////////////////////////// 49 50 /// @notice A raw leaf of the large preimage proposal merkle tree. 51 struct Leaf { 52 /// @notice The input absorbed for the block, exactly 136 bytes. 53 bytes input; 54 /// @notice The index of the block in the absorption process. 55 uint256 index; 56 /// @notice The hash of the internal state after absorbing the input. 57 bytes32 stateCommitment; 58 } 59 60 /// @notice Unpacked keys for large preimage proposals. 61 struct LargePreimageProposalKeys { 62 /// @notice The claimant of the large preimage proposal. 63 address claimant; 64 /// @notice The UUID of the large preimage proposal. 65 uint256 uuid; 66 } 67 68 /// @notice Static padding hashes. These values are persisted in storage, but are entirely immutable 69 /// after the constructor's execution. 70 bytes32[KECCAK_TREE_DEPTH] public zeroHashes; 71 /// @notice Append-only array of large preimage proposals for off-chain reference. 72 LargePreimageProposalKeys[] public proposals; 73 /// @notice Mapping of claimants to proposal UUIDs to the current branch path of the merkleization process. 74 mapping(address => mapping(uint256 => bytes32[KECCAK_TREE_DEPTH])) public proposalBranches; 75 /// @notice Mapping of claimants to proposal UUIDs to the timestamp of creation of the proposal as well as the 76 /// challenged status. 77 mapping(address => mapping(uint256 => LPPMetaData)) public proposalMetadata; 78 /// @notice Mapping of claimants to proposal UUIDs to bond amounts. 79 mapping(address => mapping(uint256 => uint256)) public proposalBonds; 80 /// @notice Mapping of claimants to proposal UUIDs to the preimage part picked up during the absorbtion process. 81 mapping(address => mapping(uint256 => bytes32)) public proposalParts; 82 /// @notice Mapping of claimants to proposal UUIDs to blocks which leaves were added to the merkle tree. 83 mapping(address => mapping(uint256 => uint64[])) public proposalBlocks; 84 85 //////////////////////////////////////////////////////////////// 86 // Constructor // 87 //////////////////////////////////////////////////////////////// 88 89 constructor(uint256 _minProposalSize, uint256 _challengePeriod) { 90 MIN_LPP_SIZE_BYTES = _minProposalSize; 91 CHALLENGE_PERIOD = _challengePeriod; 92 93 // Compute hashes in empty sparse Merkle tree. The first hash is not set, and kept as zero as the identity. 94 for (uint256 height = 0; height < KECCAK_TREE_DEPTH - 1; height++) { 95 zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height])); 96 } 97 } 98 99 //////////////////////////////////////////////////////////////// 100 // Standard Preimage Route (External) // 101 //////////////////////////////////////////////////////////////// 102 103 /// @inheritdoc IPreimageOracle 104 function readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_) { 105 require(preimagePartOk[_key][_offset], "pre-image must exist"); 106 107 // Calculate the length of the pre-image data 108 // Add 8 for the length-prefix part 109 datLen_ = 32; 110 uint256 length = preimageLengths[_key]; 111 if (_offset + 32 >= length + 8) { 112 datLen_ = length + 8 - _offset; 113 } 114 115 // Retrieve the pre-image data 116 dat_ = preimageParts[_key][_offset]; 117 } 118 119 /// @inheritdoc IPreimageOracle 120 function loadLocalData( 121 uint256 _ident, 122 bytes32 _localContext, 123 bytes32 _word, 124 uint256 _size, 125 uint256 _partOffset 126 ) 127 external 128 returns (bytes32 key_) 129 { 130 // Compute the localized key from the given local identifier. 131 key_ = PreimageKeyLib.localizeIdent(_ident, _localContext); 132 133 // Revert if the given part offset is not within bounds. 134 if (_partOffset > _size + 8 || _size > 32) { 135 revert PartOffsetOOB(); 136 } 137 138 // Prepare the local data part at the given offset 139 bytes32 part; 140 assembly { 141 // Clean the memory in [0x20, 0x40) 142 mstore(0x20, 0x00) 143 144 // Store the full local data in scratch space. 145 mstore(0x00, shl(192, _size)) 146 mstore(0x08, _word) 147 148 // Prepare the local data part at the requested offset. 149 part := mload(_partOffset) 150 } 151 152 // Store the first part with `_partOffset`. 153 preimagePartOk[key_][_partOffset] = true; 154 preimageParts[key_][_partOffset] = part; 155 // Assign the length of the preimage at the localized key. 156 preimageLengths[key_] = _size; 157 } 158 159 /// @inheritdoc IPreimageOracle 160 function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external { 161 uint256 size; 162 bytes32 key; 163 bytes32 part; 164 assembly { 165 // len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44 166 size := calldataload(0x44) 167 168 // revert if part offset >= size+8 (i.e. parts must be within bounds) 169 if iszero(lt(_partOffset, add(size, 8))) { 170 // Store "PartOffsetOOB()" 171 mstore(0x00, 0xfe254987) 172 // Revert with "PartOffsetOOB()" 173 revert(0x1c, 0x04) 174 } 175 // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory. 176 let ptr := 0x80 177 // put size as big-endian uint64 at start of pre-image 178 mstore(ptr, shl(192, size)) 179 ptr := add(ptr, 0x08) 180 // copy preimage payload into memory so we can hash and read it. 181 calldatacopy(ptr, _preimage.offset, size) 182 // Note that it includes the 8-byte big-endian uint64 length prefix. 183 // this will be zero-padded at the end, since memory at end is clean. 184 part := mload(add(sub(ptr, 0x08), _partOffset)) 185 let h := keccak256(ptr, size) // compute preimage keccak256 hash 186 // mask out prefix byte, replace with type 2 byte 187 key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x02)) 188 } 189 preimagePartOk[key][_partOffset] = true; 190 preimageParts[key][_partOffset] = part; 191 preimageLengths[key] = size; 192 } 193 194 /// @inheritdoc IPreimageOracle 195 function loadSha256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external { 196 uint256 size; 197 bytes32 key; 198 bytes32 part; 199 assembly { 200 // len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44 201 size := calldataload(0x44) 202 203 // revert if part offset >= size+8 (i.e. parts must be within bounds) 204 if iszero(lt(_partOffset, add(size, 8))) { 205 // Store "PartOffsetOOB()" 206 mstore(0, 0xfe254987) 207 // Revert with "PartOffsetOOB()" 208 revert(0x1c, 4) 209 } 210 // we leave solidity slots 0x40 and 0x60 untouched, 211 // and everything after as scratch-memory. 212 let ptr := 0x80 213 // put size as big-endian uint64 at start of pre-image 214 mstore(ptr, shl(192, size)) 215 ptr := add(ptr, 8) 216 // copy preimage payload into memory so we can hash and read it. 217 calldatacopy(ptr, _preimage.offset, size) 218 // Note that it includes the 8-byte big-endian uint64 length prefix. 219 // this will be zero-padded at the end, since memory at end is clean. 220 part := mload(add(sub(ptr, 8), _partOffset)) 221 222 // compute SHA2-256 hash with pre-compile 223 let success := 224 staticcall( 225 gas(), // Forward all available gas 226 0x02, // Address of SHA-256 precompile 227 ptr, // Start of input data in memory 228 size, // Size of input data 229 0, // Store output in scratch memory 230 0x20 // Output is always 32 bytes 231 ) 232 // Check if the staticcall succeeded 233 if iszero(success) { revert(0, 0) } 234 let h := mload(0) // get return data 235 // mask out prefix byte, replace with type 4 byte 236 key := or(and(h, not(shl(248, 0xFF))), shl(248, 4)) 237 } 238 preimagePartOk[key][_partOffset] = true; 239 preimageParts[key][_partOffset] = part; 240 preimageLengths[key] = size; 241 } 242 243 /// @inheritdoc IPreimageOracle 244 function loadBlobPreimagePart( 245 uint256 _z, 246 uint256 _y, 247 bytes calldata _commitment, 248 bytes calldata _proof, 249 uint256 _partOffset 250 ) 251 external 252 { 253 bytes32 key; 254 bytes32 part; 255 assembly { 256 // Compute the versioned hash. The SHA2 hash of the 48 byte commitment is masked with the version byte, 257 // which is currently 1. https://eips.ethereum.org/EIPS/eip-4844#parameters 258 // SAFETY: We're only reading 48 bytes from `_commitment` into scratch space, so we're not reading into the 259 // free memory ptr region. Since the exact number of btyes that is copied into scratch space is 260 // the same size as the hash input, there's no concern of dirty memory being read into the hash 261 // input. 262 calldatacopy(0x00, _commitment.offset, 0x30) 263 let success := staticcall(gas(), 0x02, 0x00, 0x30, 0x00, 0x20) 264 if iszero(success) { 265 // Store the "ShaFailed()" error selector. 266 mstore(0x00, 0xf9112969) 267 // revert with "ShaFailed()" 268 revert(0x1C, 0x04) 269 } 270 // Set the `VERSIONED_HASH_VERSION_KZG` byte = 1 in the high-order byte of the hash. 271 let versionedHash := or(and(mload(0x00), not(shl(248, 0xFF))), shl(248, 0x01)) 272 273 // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory. 274 let ptr := 0x80 275 276 // Load the inputs for the point evaluation precompile into memory. The inputs to the point evaluation 277 // precompile are packed, and not supposed to be ABI-encoded. 278 mstore(ptr, versionedHash) 279 mstore(add(ptr, 0x20), _z) 280 mstore(add(ptr, 0x40), _y) 281 calldatacopy(add(ptr, 0x60), _commitment.offset, 0x30) 282 calldatacopy(add(ptr, 0x90), _proof.offset, 0x30) 283 284 // Verify the KZG proof by calling the point evaluation precompile. If the proof is invalid, the precompile 285 // will revert. 286 success := 287 staticcall( 288 gas(), // forward all gas 289 0x0A, // point evaluation precompile address 290 ptr, // input ptr 291 0xC0, // input size = 192 bytes 292 0x00, // output ptr 293 0x00 // output size 294 ) 295 if iszero(success) { 296 // Store the "InvalidProof()" error selector. 297 mstore(0x00, 0x09bde339) 298 // revert with "InvalidProof()" 299 revert(0x1C, 0x04) 300 } 301 302 // revert if part offset >= 32+8 (i.e. parts must be within bounds) 303 if iszero(lt(_partOffset, 0x28)) { 304 // Store "PartOffsetOOB()" 305 mstore(0x00, 0xfe254987) 306 // Revert with "PartOffsetOOB()" 307 revert(0x1C, 0x04) 308 } 309 // Clean the word at `ptr + 0x28` to ensure that data out of bounds of the preimage is zero, if the part 310 // offset requires a partial read. 311 mstore(add(ptr, 0x28), 0x00) 312 // put size (32) as a big-endian uint64 at start of pre-image 313 mstore(ptr, shl(192, 0x20)) 314 // copy preimage payload into memory so we can hash and read it. 315 mstore(add(ptr, 0x08), _y) 316 // Note that it includes the 8-byte big-endian uint64 length prefix. This will be zero-padded at the end, 317 // since memory at end is guaranteed to be clean. 318 part := mload(add(ptr, _partOffset)) 319 320 // Compute the key: `keccak256(commitment ++ z)`. Since the exact number of btyes that is copied into 321 // scratch space is the same size as the hash input, there's no concern of dirty memory being read into 322 // the hash input. 323 calldatacopy(ptr, _commitment.offset, 0x30) 324 mstore(add(ptr, 0x30), _z) 325 let h := keccak256(ptr, 0x50) 326 // mask out prefix byte, replace with type 5 byte 327 key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x05)) 328 } 329 preimagePartOk[key][_partOffset] = true; 330 preimageParts[key][_partOffset] = part; 331 preimageLengths[key] = 32; 332 } 333 334 /// @inheritdoc IPreimageOracle 335 function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes calldata _input) external { 336 bytes32 res; 337 bytes32 key; 338 bytes32 part; 339 uint256 size; 340 assembly { 341 // we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory. 342 let ptr := 0x80 343 344 // copy precompile address and input into memory 345 // len(sig) + len(_partOffset) + address-offset-in-slot 346 calldatacopy(ptr, 48, 20) 347 calldatacopy(add(20, ptr), _input.offset, _input.length) 348 // compute the hash 349 let h := keccak256(ptr, add(20, _input.length)) 350 // mask out prefix byte, replace with type 6 byte 351 key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x06)) 352 353 // Call the precompile to get the result. 354 res := 355 staticcall( 356 gas(), // forward all gas 357 _precompile, 358 add(20, ptr), // input ptr 359 _input.length, 360 0x0, // Unused as we don't copy anything 361 0x00 // don't copy anything 362 ) 363 364 size := add(1, returndatasize()) 365 // revert if part offset >= size+8 (i.e. parts must be within bounds) 366 if iszero(lt(_partOffset, add(size, 8))) { 367 // Store "PartOffsetOOB()" 368 mstore(0, 0xfe254987) 369 // Revert with "PartOffsetOOB()" 370 revert(0x1c, 4) 371 } 372 373 // Reuse the `ptr` to store the preimage part: <sizePrefix ++ precompileStatus ++ returrnData> 374 // put size as big-endian uint64 at start of pre-image 375 mstore(ptr, shl(192, size)) 376 ptr := add(ptr, 0x08) 377 378 // write precompile result status to the first byte of `ptr` 379 mstore8(ptr, res) 380 // write precompile return data to the rest of `ptr` 381 returndatacopy(add(ptr, 0x01), 0x0, returndatasize()) 382 383 // compute part given ofset 384 part := mload(add(sub(ptr, 0x08), _partOffset)) 385 } 386 preimagePartOk[key][_partOffset] = true; 387 preimageParts[key][_partOffset] = part; 388 preimageLengths[key] = size; 389 } 390 391 //////////////////////////////////////////////////////////////// 392 // Large Preimage Proposals (External) // 393 //////////////////////////////////////////////////////////////// 394 395 /// @notice Returns the length of the `proposals` array 396 function proposalCount() external view returns (uint256 count_) { 397 count_ = proposals.length; 398 } 399 400 /// @notice Returns the length of the array with the block numbers of `addLeavesLPP` calls for a given large 401 /// preimage proposal. 402 function proposalBlocksLen(address _claimant, uint256 _uuid) external view returns (uint256 len_) { 403 len_ = proposalBlocks[_claimant][_uuid].length; 404 } 405 406 /// @notice Returns the length of the large preimage proposal challenge period. 407 function challengePeriod() external view returns (uint256 challengePeriod_) { 408 challengePeriod_ = CHALLENGE_PERIOD; 409 } 410 411 /// @notice Returns the minimum size (in bytes) of a large preimage proposal. 412 function minProposalSize() external view returns (uint256 minProposalSize_) { 413 minProposalSize_ = MIN_LPP_SIZE_BYTES; 414 } 415 416 /// @notice Initialize a large preimage proposal. Must be called before adding any leaves. 417 function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external payable { 418 // The bond provided must be at least `MIN_BOND_SIZE`. 419 if (msg.value < MIN_BOND_SIZE) revert InsufficientBond(); 420 421 // The caller of `addLeavesLPP` must be an EOA, so that the call inputs are always available in block bodies. 422 if (msg.sender != tx.origin) revert NotEOA(); 423 424 // The part offset must be within the bounds of the claimed size + 8. 425 if (_partOffset >= _claimedSize + 8) revert PartOffsetOOB(); 426 427 // The claimed size must be at least `MIN_LPP_SIZE_BYTES`. 428 if (_claimedSize < MIN_LPP_SIZE_BYTES) revert InvalidInputSize(); 429 430 // Initialize the proposal metadata. 431 LPPMetaData metaData = proposalMetadata[msg.sender][_uuid]; 432 proposalMetadata[msg.sender][_uuid] = metaData.setPartOffset(_partOffset).setClaimedSize(_claimedSize); 433 proposals.push(LargePreimageProposalKeys(msg.sender, _uuid)); 434 435 // Assign the bond to the proposal. 436 proposalBonds[msg.sender][_uuid] = msg.value; 437 } 438 439 /// @notice Adds a contiguous list of keccak state matrices to the merkle tree. 440 function addLeavesLPP( 441 uint256 _uuid, 442 uint256 _inputStartBlock, 443 bytes calldata _input, 444 bytes32[] calldata _stateCommitments, 445 bool _finalize 446 ) 447 external 448 { 449 // If we're finalizing, pad the input for the submitter. If not, copy the input into memory verbatim. 450 bytes memory input; 451 if (_finalize) { 452 input = LibKeccak.pad(_input); 453 } else { 454 input = _input; 455 } 456 457 // Pull storage variables onto the stack / into memory for operations. 458 bytes32[KECCAK_TREE_DEPTH] memory branch = proposalBranches[msg.sender][_uuid]; 459 LPPMetaData metaData = proposalMetadata[msg.sender][_uuid]; 460 uint256 blocksProcessed = metaData.blocksProcessed(); 461 462 // The caller of `addLeavesLPP` must be an EOA. 463 if (msg.sender != tx.origin) revert NotEOA(); 464 465 // Revert if the proposal has not been initialized. 0-size preimages are *not* allowed. 466 if (metaData.claimedSize() == 0) revert NotInitialized(); 467 468 // Revert if the proposal has already been finalized. No leaves can be added after this point. 469 if (metaData.timestamp() != 0) revert AlreadyFinalized(); 470 471 // Revert if the starting block is not the next block to be added. This is to aid submitters in ensuring that 472 // they don't corrupt an in-progress proposal by submitting input out of order. 473 if (blocksProcessed != _inputStartBlock) revert WrongStartingBlock(); 474 475 // Attempt to extract the preimage part from the input data, if the part offset is present in the current 476 // chunk of input. This function has side effects, and will persist the preimage part to the caller's large 477 // preimage proposal storage if the part offset is present in the input data. 478 _extractPreimagePart(_input, _uuid, _finalize, metaData); 479 480 assembly { 481 let inputLen := mload(input) 482 let inputPtr := add(input, 0x20) 483 484 // The input length must be a multiple of 136 bytes 485 // The input lenth / 136 must be equal to the number of state commitments. 486 if or(mod(inputLen, 136), iszero(eq(_stateCommitments.length, div(inputLen, 136)))) { 487 // Store "InvalidInputSize()" error selector 488 mstore(0x00, 0x7b1daf1) 489 revert(0x1C, 0x04) 490 } 491 492 // Allocate a hashing buffer the size of the leaf preimage. 493 let hashBuf := mload(0x40) 494 mstore(0x40, add(hashBuf, 0xC8)) 495 496 for { let i := 0 } lt(i, inputLen) { i := add(i, 136) } { 497 // Copy the leaf preimage into the hashing buffer. 498 let inputStartPtr := add(inputPtr, i) 499 mstore(hashBuf, mload(inputStartPtr)) 500 mstore(add(hashBuf, 0x20), mload(add(inputStartPtr, 0x20))) 501 mstore(add(hashBuf, 0x40), mload(add(inputStartPtr, 0x40))) 502 mstore(add(hashBuf, 0x60), mload(add(inputStartPtr, 0x60))) 503 mstore(add(hashBuf, 0x80), mload(add(inputStartPtr, 0x80))) 504 mstore(add(hashBuf, 136), blocksProcessed) 505 mstore(add(hashBuf, 168), calldataload(add(_stateCommitments.offset, shl(0x05, div(i, 136))))) 506 507 // Hash the leaf preimage to get the node to add. 508 let node := keccak256(hashBuf, 0xC8) 509 510 // Increment the number of blocks processed. 511 blocksProcessed := add(blocksProcessed, 0x01) 512 513 // Add the node to the tree. 514 let size := blocksProcessed 515 for { let height := 0x00 } lt(height, shl(0x05, KECCAK_TREE_DEPTH)) { height := add(height, 0x20) } { 516 if and(size, 0x01) { 517 mstore(add(branch, height), node) 518 break 519 } 520 521 // Hash the node at `height` in the branch and the node together. 522 mstore(0x00, mload(add(branch, height))) 523 mstore(0x20, node) 524 node := keccak256(0x00, 0x40) 525 size := shr(0x01, size) 526 } 527 } 528 } 529 530 // Do not allow for posting preimages larger than the merkle tree can support. The incremental merkle tree 531 // algorithm only supports 2**height - 1 leaves, the right most leaf must always be kept empty. 532 // Reference: https://daejunpark.github.io/papers/deposit.pdf - Page 10, Section 5.1. 533 if (blocksProcessed > MAX_LEAF_COUNT) revert TreeSizeOverflow(); 534 535 // Update the proposal metadata to include the number of blocks processed and total bytes processed. 536 metaData = metaData.setBlocksProcessed(uint32(blocksProcessed)).setBytesProcessed( 537 uint32(_input.length + metaData.bytesProcessed()) 538 ); 539 // If the proposal is being finalized, set the timestamp to the current block timestamp. This begins the 540 // challenge period, which must be waited out before the proposal can be finalized. 541 if (_finalize) { 542 metaData = metaData.setTimestamp(uint64(block.timestamp)); 543 544 // If the number of bytes processed is not equal to the claimed size, the proposal cannot be finalized. 545 if (metaData.bytesProcessed() != metaData.claimedSize()) revert InvalidInputSize(); 546 } 547 548 // Perist the latest branch to storage. 549 proposalBranches[msg.sender][_uuid] = branch; 550 // Persist the block number that these leaves were added in. This assists off-chain observers in reconstructing 551 // the proposal merkle tree by querying block bodies. 552 proposalBlocks[msg.sender][_uuid].push(uint64(block.number)); 553 // Persist the updated metadata to storage. 554 proposalMetadata[msg.sender][_uuid] = metaData; 555 } 556 557 /// @notice Challenge a keccak256 block that was committed to in the merkle tree. 558 function challengeLPP( 559 address _claimant, 560 uint256 _uuid, 561 LibKeccak.StateMatrix memory _stateMatrix, 562 Leaf calldata _preState, 563 bytes32[] calldata _preStateProof, 564 Leaf calldata _postState, 565 bytes32[] calldata _postStateProof 566 ) 567 external 568 { 569 // Verify that both leaves are present in the merkle tree. 570 bytes32 root = getTreeRootLPP(_claimant, _uuid); 571 if ( 572 !( 573 _verify(_preStateProof, root, _preState.index, _hashLeaf(_preState)) 574 && _verify(_postStateProof, root, _postState.index, _hashLeaf(_postState)) 575 ) 576 ) revert InvalidProof(); 577 578 // Verify that the prestate passed matches the intermediate state claimed in the leaf. 579 if (keccak256(abi.encode(_stateMatrix)) != _preState.stateCommitment) revert InvalidPreimage(); 580 581 // Verify that the pre/post state are contiguous. 582 if (_preState.index + 1 != _postState.index) revert StatesNotContiguous(); 583 584 // Absorb and permute the input bytes. 585 LibKeccak.absorb(_stateMatrix, _postState.input); 586 LibKeccak.permutation(_stateMatrix); 587 588 // Verify that the post state hash doesn't match the expected hash. 589 if (keccak256(abi.encode(_stateMatrix)) == _postState.stateCommitment) revert PostStateMatches(); 590 591 // Mark the keccak claim as countered. 592 proposalMetadata[_claimant][_uuid] = proposalMetadata[_claimant][_uuid].setCountered(true); 593 594 // Pay out the bond to the challenger. 595 _payoutBond(_claimant, _uuid, msg.sender); 596 } 597 598 /// @notice Challenge the first keccak256 block that was absorbed. 599 function challengeFirstLPP( 600 address _claimant, 601 uint256 _uuid, 602 Leaf calldata _postState, 603 bytes32[] calldata _postStateProof 604 ) 605 external 606 { 607 // Verify that the leaf is present in the merkle tree. 608 bytes32 root = getTreeRootLPP(_claimant, _uuid); 609 if (!_verify(_postStateProof, root, _postState.index, _hashLeaf(_postState))) revert InvalidProof(); 610 611 // The poststate index must be 0 in order to challenge it with this function. 612 if (_postState.index != 0) revert StatesNotContiguous(); 613 614 // Absorb and permute the input bytes into a fresh state matrix. 615 LibKeccak.StateMatrix memory stateMatrix; 616 LibKeccak.absorb(stateMatrix, _postState.input); 617 LibKeccak.permutation(stateMatrix); 618 619 // Verify that the post state hash doesn't match the expected hash. 620 if (keccak256(abi.encode(stateMatrix)) == _postState.stateCommitment) revert PostStateMatches(); 621 622 // Mark the keccak claim as countered. 623 proposalMetadata[_claimant][_uuid] = proposalMetadata[_claimant][_uuid].setCountered(true); 624 625 // Pay out the bond to the challenger. 626 _payoutBond(_claimant, _uuid, msg.sender); 627 } 628 629 /// @notice Finalize a large preimage proposal after the challenge period has passed. 630 function squeezeLPP( 631 address _claimant, 632 uint256 _uuid, 633 LibKeccak.StateMatrix memory _stateMatrix, 634 Leaf calldata _preState, 635 bytes32[] calldata _preStateProof, 636 Leaf calldata _postState, 637 bytes32[] calldata _postStateProof 638 ) 639 external 640 { 641 LPPMetaData metaData = proposalMetadata[_claimant][_uuid]; 642 643 // Check if the proposal was countered. 644 if (metaData.countered()) revert BadProposal(); 645 646 // Check if the challenge period has passed since the proposal was finalized. 647 if (block.timestamp - metaData.timestamp() <= CHALLENGE_PERIOD) revert ActiveProposal(); 648 649 // Verify that both leaves are present in the merkle tree. 650 bytes32 root = getTreeRootLPP(_claimant, _uuid); 651 if ( 652 !( 653 _verify(_preStateProof, root, _preState.index, _hashLeaf(_preState)) 654 && _verify(_postStateProof, root, _postState.index, _hashLeaf(_postState)) 655 ) 656 ) revert InvalidProof(); 657 658 // Verify that the prestate passed matches the intermediate state claimed in the leaf. 659 if (keccak256(abi.encode(_stateMatrix)) != _preState.stateCommitment) revert InvalidPreimage(); 660 661 // Verify that the pre/post state are contiguous. 662 if (_preState.index + 1 != _postState.index || _postState.index != metaData.blocksProcessed() - 1) { 663 revert StatesNotContiguous(); 664 } 665 666 // Absorb and permute the input bytes. We perform no final verification on the state matrix here, since the 667 // proposal has passed the challenge period and is considered valid. 668 LibKeccak.absorb(_stateMatrix, _postState.input); 669 LibKeccak.permutation(_stateMatrix); 670 bytes32 finalDigest = LibKeccak.squeeze(_stateMatrix); 671 assembly { 672 finalDigest := or(and(finalDigest, not(shl(248, 0xFF))), shl(248, 0x02)) 673 } 674 675 // Write the preimage part to the authorized preimage parts mapping. 676 uint256 partOffset = metaData.partOffset(); 677 preimagePartOk[finalDigest][partOffset] = true; 678 preimageParts[finalDigest][partOffset] = proposalParts[_claimant][_uuid]; 679 preimageLengths[finalDigest] = metaData.claimedSize(); 680 681 // Pay out the bond to the claimant. 682 _payoutBond(_claimant, _uuid, _claimant); 683 } 684 685 /// @notice Gets the current merkle root of the large preimage proposal tree. 686 function getTreeRootLPP(address _owner, uint256 _uuid) public view returns (bytes32 treeRoot_) { 687 uint256 size = proposalMetadata[_owner][_uuid].blocksProcessed(); 688 for (uint256 height = 0; height < KECCAK_TREE_DEPTH; height++) { 689 if ((size & 1) == 1) { 690 treeRoot_ = keccak256(abi.encode(proposalBranches[_owner][_uuid][height], treeRoot_)); 691 } else { 692 treeRoot_ = keccak256(abi.encode(treeRoot_, zeroHashes[height])); 693 } 694 size >>= 1; 695 } 696 } 697 698 /// @notice Attempts to persist the preimage part to the caller's large preimage proposal storage, if the preimage 699 /// part is present in the input data being posted. 700 /// @param _input The portion of the preimage being posted. 701 /// @param _uuid The UUID of the large preimage proposal. 702 /// @param _finalize Whether or not the proposal is being finalized in the current call. 703 /// @param _metaData The metadata of the large preimage proposal. 704 function _extractPreimagePart( 705 bytes calldata _input, 706 uint256 _uuid, 707 bool _finalize, 708 LPPMetaData _metaData 709 ) 710 internal 711 { 712 uint256 offset = _metaData.partOffset(); 713 uint256 claimedSize = _metaData.claimedSize(); 714 uint256 currentSize = _metaData.bytesProcessed(); 715 716 // Check if the part offset is present in the input data being posted. If it is, assign the part to the mapping. 717 if (offset < 8 && currentSize == 0) { 718 bytes32 preimagePart; 719 assembly { 720 mstore(0x00, shl(192, claimedSize)) 721 mstore(0x08, calldataload(_input.offset)) 722 preimagePart := mload(offset) 723 } 724 proposalParts[msg.sender][_uuid] = preimagePart; 725 } else if (offset >= 8 && (offset = offset - 8) >= currentSize && offset < currentSize + _input.length) { 726 uint256 relativeOffset = offset - currentSize; 727 728 // Revert if the full preimage part is not available in the data we're absorbing. The submitter must 729 // supply data that contains the full preimage part so that no partial preimage parts are stored in the 730 // oracle. Partial parts are *only* allowed at the tail end of the preimage, where no more data is available 731 // to be absorbed. 732 if (relativeOffset + 32 >= _input.length && !_finalize) revert PartOffsetOOB(); 733 734 // If the preimage part is in the data we're about to absorb, persist the part to the caller's large 735 // preimaage metadata. 736 bytes32 preimagePart; 737 assembly { 738 preimagePart := calldataload(add(_input.offset, relativeOffset)) 739 } 740 proposalParts[msg.sender][_uuid] = preimagePart; 741 } 742 } 743 744 /// @notice Check if leaf` at `index` verifies against the Merkle `root` and `branch`. 745 /// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_valid_merkle_branch 746 function _verify( 747 bytes32[] calldata _proof, 748 bytes32 _root, 749 uint256 _index, 750 bytes32 _leaf 751 ) 752 internal 753 pure 754 returns (bool isValid_) 755 { 756 /// @solidity memory-safe-assembly 757 assembly { 758 function hashTwo(a, b) -> hash { 759 mstore(0x00, a) 760 mstore(0x20, b) 761 hash := keccak256(0x00, 0x40) 762 } 763 764 let value := _leaf 765 for { let i := 0x00 } lt(i, KECCAK_TREE_DEPTH) { i := add(i, 0x01) } { 766 let branchValue := calldataload(add(_proof.offset, shl(0x05, i))) 767 768 switch and(shr(i, _index), 0x01) 769 case 1 { value := hashTwo(branchValue, value) } 770 default { value := hashTwo(value, branchValue) } 771 } 772 773 isValid_ := eq(value, _root) 774 } 775 } 776 777 /// @notice Pay out a proposal's bond. Reverts if the transfer fails. 778 function _payoutBond(address _claimant, uint256 _uuid, address _to) internal { 779 // Pay out the bond to the claimant. 780 uint256 bond = proposalBonds[_claimant][_uuid]; 781 proposalBonds[_claimant][_uuid] = 0; 782 (bool success,) = _to.call{ value: bond }(""); 783 if (!success) revert BondTransferFailed(); 784 } 785 786 /// @notice Hashes leaf data for the preimage proposals tree 787 function _hashLeaf(Leaf memory _leaf) internal pure returns (bytes32 leaf_) { 788 leaf_ = keccak256(abi.encodePacked(_leaf.input, _leaf.index, _leaf.stateCommitment)); 789 } 790 }