Vulnerability: The Compressed Block Data Is Not Verified Against Data in the Prover During Data Submission  Acknowledged
Severity: medium

Description:
When the sequencer submits the batched block data with the `submitData` function, it's expected to check that the submitted commitment of the compressed block data `keccak(_submissionData.compressedData)` and the commitment of the block data used in the prover (snarkHash) commit to the same data. This is done by proof of equivalence; the `x` is calculated by hashing `keccak(_submissionData.compressedData)` and `snarkHash`, and `y` is provided by the prover. Then it's verified that `P(x) = y`, where `P` is a polynomial that encodes the compressed data (_submissionData.compressedData). However, in the `submitData` function, `y` is evaluated by `_calculateY` but it is not checked against the `y` provided by the prover. In fact, the prover doesn't provide `y` to the function; instead `x` and `y` are provided to the prover who would evaluate `y'` and compare it with `y` from the contract, then `x` and `y` are included in the public input for the proof verification in the finalization.\\n```\\nshnarf = keccak256(\\n      abi.encode(\\n        shnarf,\\n        _submissionData.snarkHash,\\n        _submissionData.finalStateRootHash,\\n        compressedDataComputedX,\\n        _calculateY(_submissionData.compressedData, compressedDataComputedX)\\n      )\\n );     \\n```\\n\\nThe only difference is if the two commitments don't commit to the same block data (meaning the data submitted doesn't match the data used in the prover), `submitData` would fail - while in the current implementation, it would fail in the proof verification during the finalization. As a result, if the data submitted doesn't match the data in the prover in the finalization, the operator has to submit the correct data again in order to finalize it. Linea stated they will verify it in the data submission, once EIP-4844 is implemented.\\n```\\nfunction \\_submitData(SubmissionData calldata \\_submissionData) internal returns (bytes32 shnarf) {\\n shnarf = dataShnarfHashes[\\_submissionData.dataParentHash];\\n\\n bytes32 parentFinalStateRootHash = dataFinalStateRootHashes[\\_submissionData.dataParentHash];\\n uint256 lastFinalizedBlock = currentL2BlockNumber;\\n\\n if (\\_submissionData.firstBlockInData <= lastFinalizedBlock) {\\n revert FirstBlockLessThanOrEqualToLastFinalizedBlock(\\_submissionData.firstBlockInData, lastFinalizedBlock);\\n }\\n\\n if (\\_submissionData.firstBlockInData > \\_submissionData.finalBlockInData) {\\n revert FirstBlockGreaterThanFinalBlock(\\_submissionData.firstBlockInData, \\_submissionData.finalBlockInData);\\n }\\n\\n if (\\_submissionData.parentStateRootHash != parentFinalStateRootHash) {\\n revert StateRootHashInvalid(parentFinalStateRootHash, \\_submissionData.parentStateRootHash);\\n }\\n\\n bytes32 currentDataHash = keccak256(\\_submissionData.compressedData);\\n\\n if (dataFinalStateRootHashes[currentDataHash] != EMPTY\\_HASH) {\\n revert DataAlreadySubmitted(currentDataHash);\\n }\\n\\n dataParents[currentDataHash] = \\_submissionData.dataParentHash;\\n dataFinalStateRootHashes[currentDataHash] = \\_submissionData.finalStateRootHash;\\n\\n bytes32 compressedDataComputedX = keccak256(abi.encode(\\_submissionData.snarkHash, currentDataHash));\\n\\n shnarf = keccak256(\\n abi.encode(\\n shnarf,\\n \\_submissionData.snarkHash,\\n \\_submissionData.finalStateRootHash,\\n compressedDataComputedX,\\n \\_calculateY(\\_submissionData.compressedData, compressedDataComputedX)\\n )\\n );\\n\\n dataShnarfHashes[currentDataHash] = shnarf;\\n\\n emit DataSubmitted(currentDataHash, \\_submissionData.firstBlockInData, \\_submissionData.finalBlockInData);\\n}\\n```\\n\\n```\\nfunction \\_calculateY(\\n bytes calldata \\_data,\\n bytes32 \\_compressedDataComputedX\\n) internal pure returns (bytes32 compressedDataComputedY) {\\n if (\\_data.length % 0x20 != 0) {\\n revert BytesLengthNotMultipleOf32();\\n }\\n\\n bytes4 errorSelector = ILineaRollup.FirstByteIsNotZero.selector;\\n assembly {\\n for {\\n let i := \\_data.length\\n } gt(i, 0) {\\n\\n } {\\n i := sub(i, 0x20)\\n let chunk := calldataload(add(\\_data.offset, i))\\n if iszero(iszero(and(chunk, 0xFF00000000000000000000000000000000000000000000000000000000000000))) {\\n let ptr := mload(0x40)\\n mstore(ptr, errorSelector)\\n revert(ptr, 0x4)\\n }\\n compressedDataComputedY := addmod(\\n mulmod(compressedDataComputedY, \\_compressedDataComputedX, Y\\_MODULUS),\\n chunk,\\n Y\\_MODULUS\\n )\\n }\\n }\\n}\\n```\\n

Impact:

Recommended mitigation:
Add the compressed block data verification in the `submitData` function.