diff --git a/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol b/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol index 6cb5cc986..dd893253b 100644 --- a/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol +++ b/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol @@ -17,7 +17,34 @@ contract DummyEigenDABridge is IEigenDABridge { return implementationContract; } - function verifyBlobLeaf(bytes calldata) external view returns (bool) { + function verifyBlobLeaf(MerkleProofInput calldata merkleProof) external view returns (bool) { + // Inspired by eigenlayer contracts Merkle.verifyInclusionKeccak + // https://github.com/Layr-Labs/eigenlayer-contracts/blob/3f3f83bd194b3bdc77d06d8fe6b101fafc3bcfd5/src/contracts/libraries/Merkle.sol + uint256 index = merkleProof.index; + bytes memory inclusionProof = merkleProof.inclusionProof; + require(inclusionProof.length % 32 == 0, "proof length not multiple of 32"); + bytes32 computedHash = merkleProof.leaf; + uint256 length = inclusionProof.length; + for (uint256 i = 32; i <= length; i += 32) { + if (index % 2 == 0) { + // if ith bit of index is 0, then computedHash is a left sibling + assembly { + mstore(0x00, computedHash) + mstore(0x20, mload(add(inclusionProof, i))) + computedHash := keccak256(0x00, 0x40) + index := div(index, 2) + } + } else { + // if ith bit of index is 1, then computedHash is a right sibling + assembly { + mstore(0x00, mload(add(inclusionProof, i))) + mstore(0x20, computedHash) + computedHash := keccak256(0x00, 0x40) + index := div(index, 2) + } + } + } + require(computedHash == merkleProof.batchRoot, "invalid proof"); return true; } } diff --git a/da-contracts/contracts/da-layers/eigenda/EigenDAAttestationLib.sol b/da-contracts/contracts/da-layers/eigenda/EigenDAAttestationLib.sol index 4399ac1c6..5bb1fe070 100644 --- a/da-contracts/contracts/da-layers/eigenda/EigenDAAttestationLib.sol +++ b/da-contracts/contracts/da-layers/eigenda/EigenDAAttestationLib.sol @@ -24,7 +24,7 @@ abstract contract EigenDAAttestationLib { implementation = bridge.implementation(); } - function _attest(bytes memory input) internal virtual { + function _attest(IEigenDABridge.MerkleProofInput memory input) internal virtual { if (!bridge.verifyBlobLeaf(input)) revert InvalidAttestationProof(); /*attestations[input.leaf] = AttestationData( implementation.rangeStartBlocks(input.rangeHash) + uint32(input.dataRootIndex) + 1, diff --git a/da-contracts/contracts/da-layers/eigenda/EigenDAL1Validator.sol b/da-contracts/contracts/da-layers/eigenda/EigenDAL1Validator.sol index cb9b40295..75f8c5d87 100644 --- a/da-contracts/contracts/da-layers/eigenda/EigenDAL1Validator.sol +++ b/da-contracts/contracts/da-layers/eigenda/EigenDAL1Validator.sol @@ -15,7 +15,7 @@ contract EigenDAL1Validator is IL1DAValidator, EigenDAAttestationLib { function checkDA( uint256, // _chainId uint256, // _batchNumber - bytes32 l2DAValidatorOutputHash, // TODO: Maybe we don't need this + bytes32, // _l2DAValidatorOutputHash, // TODO: Maybe we don't need this bytes calldata operatorDAInput, uint256 maxBlobsSupported ) external override returns (L1DAValidatorOutput memory output) { @@ -29,10 +29,13 @@ contract EigenDAL1Validator is IL1DAValidator, EigenDAAttestationLib { output.stateDiffHash = stateDiffHash; - /*IEigenDABridge.MerkleProofInput memory input = abi.decode(operatorDAInput[32:], (IEigenDABridge.MerkleProofInput)); - if (l2DAValidatorOutputHash != keccak256(abi.encodePacked(output.stateDiffHash, input.leaf))) + IEigenDABridge.MerkleProofInput memory input = abi.decode( + operatorDAInput[32:], + (IEigenDABridge.MerkleProofInput) + ); + /*if (l2DAValidatorOutputHash != keccak256(abi.encodePacked(output.stateDiffHash, input.leaf))) revert InvalidValidatorOutputHash();*/ //TODO: Maybe we don't need this - _attest(operatorDAInput[32:]); + _attest(input); output.blobsLinearHashes = new bytes32[](maxBlobsSupported); output.blobsOpeningCommitments = new bytes32[](maxBlobsSupported); diff --git a/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol b/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol index bfcd3d300..11947e045 100644 --- a/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol +++ b/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol @@ -5,42 +5,14 @@ import {IImplementation} from "./IImplementation.sol"; interface IEigenDABridge { // solhint-disable-next-line gas-struct-packing - struct Message { - // single-byte prefix representing the message type - bytes1 messageType; - // address of message sender - bytes32 from; - // address of message receiver - bytes32 to; - // origin chain code - uint32 originDomain; - // destination chain code - uint32 destinationDomain; - // data being sent - bytes data; - // nonce - uint64 messageId; - } struct MerkleProofInput { - // proof of inclusion for the data root - bytes32[] dataRootProof; - // proof of inclusion of leaf within blob/bridge root - bytes32[] leafProof; - // abi.encodePacked(startBlock, endBlock) of header range commitment on implementation - bytes32 rangeHash; - // index of the data root in the commitment tree - uint256 dataRootIndex; - // blob root to check proof against, or reconstruct the data root - bytes32 blobRoot; - // bridge root to check proof against, or reconstruct the data root - bytes32 bridgeRoot; - // leaf being proven + bytes32 batchRoot; bytes32 leaf; - // index of the leaf in the blob/bridge root tree - uint256 leafIndex; + uint256 index; + bytes inclusionProof; } function implementation() external view returns (IImplementation implementation); - function verifyBlobLeaf(bytes calldata input) external view returns (bool); + function verifyBlobLeaf(MerkleProofInput calldata input) external view returns (bool); }