Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into feat/dispute-kit-fo…
Browse files Browse the repository at this point in the history
…rest
  • Loading branch information
jaybuidl committed May 19, 2022
2 parents c302740 + b70f8b2 commit 1ce5286
Show file tree
Hide file tree
Showing 7 changed files with 2,268 additions and 1,841 deletions.
9 changes: 5 additions & 4 deletions contracts/src/bridge/FastBridgeSenderToEthereum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe

ticketID = currentTicketID++;

(bytes32 messageHash, bytes memory messageData) = _encode(ticketID, _receiver, _calldata);
(bytes32 messageHash, bytes memory messageData) = _encode(ticketID, block.number, _receiver, _calldata);
emit OutgoingMessage(ticketID, block.number, _receiver, messageHash, messageData);

tickets[ticketID] = Ticket({messageHash: messageHash, blockNumber: block.number, sentSafe: false});
Expand All @@ -102,7 +102,7 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
require(ticket.messageHash != 0, "Ticket does not exist.");
require(ticket.sentSafe == false, "Ticket already sent safely.");

(bytes32 messageHash, bytes memory messageData) = _encode(_ticketID, _receiver, _calldata);
(bytes32 messageHash, bytes memory messageData) = _encode(_ticketID, ticket.blockNumber, _receiver, _calldata);
require(ticket.messageHash == messageHash, "Invalid message for ticketID.");

// Safe Bridge message envelope
Expand Down Expand Up @@ -132,13 +132,14 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe

function _encode(
uint256 _ticketID,
uint256 _blockNumber,
address _receiver,
bytes memory _calldata
) internal view returns (bytes32 messageHash, bytes memory messageData) {
) internal pure returns (bytes32 messageHash, bytes memory messageData) {
// Encode the receiver address with the function signature + arguments i.e calldata
messageData = abi.encode(_receiver, _calldata);

// Compute the hash over the message header (ticketID, blockNumber) and body (data).
messageHash = keccak256(abi.encode(_ticketID, block.number, messageData));
messageHash = keccak256(abi.encode(_ticketID, _blockNumber, messageData));
}
}
71 changes: 71 additions & 0 deletions contracts/src/bridge/merkle/MerkleProof.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT

/**
* @authors: [@shotaronowhere]
* @reviewers: []
* @auditors: []
* @bounties: []
* @deployments: []
*/

pragma solidity ^0.8.0;

/**
* @title MerkleProof
* @author Shotaro N. - <shawtarohgn@gmail.com>
* @dev A set of funcitons to verify merkle proofs.
*/
contract MerkleProof {
/** @dev Validates membership of leaf in merkle tree with merkle proof.
* @param proof The merkle proof.
* @param leaf The leaf to validate membership in merkle tree.
* @param merkleRoot The root of the merkle tree.
*/
function validateProof(
bytes32[] memory proof,
bytes32 leaf,
bytes32 merkleRoot
) internal pure returns (bool) {
return (merkleRoot == calculateRoot(proof, leaf));
}

/** @dev Validates membership of leaf in merkle tree with merkle proof.
* @param proof The merkle proof.
* @param data The data to validate membership in merkle tree.
* @param merkleRoot The root of the merkle tree.
*/
function validateProof(
bytes32[] memory proof,
bytes memory data,
bytes32 merkleRoot
) public pure returns (bool) {
return validateProof(proof, sha256(data), merkleRoot);
}

/** @dev Calculates merkle root from proof.
* @param proof The merkle proof.
* @param leaf The leaf to validate membership in merkle tree..
*/
function calculateRoot(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
uint256 proofLength = proof.length;
require(proofLength <= 64, "Invalid Proof");
bytes32 h = leaf;
for (uint256 i = 0; i < proofLength; i++) {
bytes32 proofElement = proof[i];
// effecient hash
if (proofElement > h)
assembly {
mstore(0x00, h)
mstore(0x20, proofElement)
h := keccak256(0x00, 0x40)
}
else
assembly {
mstore(0x00, proofElement)
mstore(0x20, h)
h := keccak256(0x00, 0x40)
}
}
return h;
}
}
130 changes: 130 additions & 0 deletions contracts/src/bridge/merkle/MerkleTreeHistory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// SPDX-License-Identifier: MIT

/**
* @authors: [@shotaronowhere]
* @reviewers: []
* @auditors: []
* @bounties: []
* @deployments: []
*/

pragma solidity ^0.8.0;

/**
* @title MerkleTreeHistory
* @author Shotaro N. - <shawtarohgn@gmail.com>
* @dev An efficient append only merkle tree with history.
*/
contract MerkleTreeHistory {
// ***************************** //
// * Storage * //
// ***************************** //

// merkle tree representation
// supports 2^64 messages.
bytes32[64] public branch;
uint256 public count;

// block number => merkle root history
mapping(uint256 => bytes32) private history;

// ************************************* //
// * State Modifiers * //
// ************************************* //

/** @dev Append data into merkle tree.
* `O(log(n))` where
* `n` is the number of leaves.
* Note: Although each insertion is O(log(n)),
* Complexity of n insertions is O(n).
* @param data The data to insert in the merkle tree.
*/
function append(bytes memory data) public {
// Differentiate leaves from interior nodes with different
// hash functions to prevent 2nd order pre-image attack.
// https://flawed.net.nz/2018/02/21/attacking-merkle-trees-with-a-second-preimage-attack/
bytes32 leaf = sha256(data);
uint256 size = count + 1;
count = size;
uint256 hashBitField = (size ^ (size - 1)) & size;
uint256 height;
while ((hashBitField & 1) == 0) {
bytes32 node = branch[height];
if (node > leaf)
assembly {
// effecient hash
mstore(0x00, leaf)
mstore(0x20, node)
leaf := keccak256(0x00, 0x40)
}
else
assembly {
// effecient hash
mstore(0x00, node)
mstore(0x20, leaf)
leaf := keccak256(0x00, 0x40)
}
hashBitField /= 2;
height = height + 1;
}
branch[height] = leaf;
}

/** @dev Saves the merkle root state in history and resets.
* `O(log(n))` where
* `n` is the number of leaves.
*/
function reset() internal {
history[block.number] = getMerkleRoot();
count = 0;
}

/** @dev Gets the merkle root history
* `O(log(n))` where
* `n` is the number of leaves.
* @param blocknumber requested blocknumber.
*/
function getMerkleRootHistory(uint256 blocknumber) public view returns (bytes32) {
if (blocknumber == block.number) return getMerkleRoot();

return history[blocknumber];
}

/** @dev Gets the current merkle root.
* `O(log(n))` where
* `n` is the number of leaves.
*/
function getMerkleRoot() public view returns (bytes32) {
bytes32 node;
uint256 size = count;
uint256 height = 0;
bool isFirstHash = true;
while (size > 0) {
if ((size & 1) == 1) {
// avoid redundant calculation
if (isFirstHash) {
node = branch[height];
isFirstHash = false;
} else {
bytes32 hash = branch[height];
// effecient hash
if (hash > node)
assembly {
mstore(0x00, node)
mstore(0x20, hash)
node := keccak256(0x00, 0x40)
}
else
assembly {
mstore(0x00, hash)
mstore(0x20, node)
node := keccak256(0x00, 0x40)
}
}
}
size /= 2;
height++;
}
return node;
}
}
Loading

0 comments on commit 1ce5286

Please sign in to comment.