Skip to content

Commit

Permalink
Added optimized byte comparison function to Bridge contract (#930)
Browse files Browse the repository at this point in the history
* Added optimized byte comparison function

* Ahmet's optimization

* fixed offset <= len

* make genesis

* edge case tests added
  • Loading branch information
erdkocak authored Jul 31, 2024
1 parent f98545f commit 44c10f0
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 23 deletions.

Large diffs are not rendered by default.

34 changes: 25 additions & 9 deletions crates/evm/src/evm/system_contracts/src/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -166,22 +166,38 @@ contract Bridge is Ownable2StepUpgradeable {
emit OperatorUpdated(operator, _operator);
}

/// @notice Checks if two byte sequences are equal
/// @dev This is not efficient, and a better approach would be doing a hash based comparison but as this is ran in a zkEVM, hashing is inefficient
/// @notice Checks if two byte sequences are equal in chunks of 32 bytes
/// @dev This approach compares chunks of 32 bytes using bytes32 equality checks for optimization
/// @param a First byte sequence
/// @param b Second byte sequence
function isBytesEqual(bytes memory a, bytes memory b) internal pure returns (bool result) {
require(a.length == b.length, "Lengths do not match");
uint256 len = a.length;
if (len != b.length) {
return false;
}

uint256 offset = 32;
bytes32 chunkA;
bytes32 chunkB;
while (offset <= len) {
assembly {
chunkA := mload(add(a, offset))
chunkB := mload(add(b, offset))
offset := add(offset, 32)
}
if (chunkA != chunkB) {
return false;
}
}

// Cannot use keccak as its costly in ZK environment
uint length = a.length;
for (uint i = 0; i < length; i++) {
// Check remaining bytes (if any)
for (uint i = offset - 32; i < len; i++) {
if (a[i] != b[i]) {
result = false;
return result;
return false;
}
}
result = true;

return true;
}

function extractRecipientAddress(bytes memory _script) internal view returns (address) {
Expand Down
31 changes: 26 additions & 5 deletions crates/evm/src/evm/system_contracts/test/Bridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ contract BridgeTest is Test {
doDeposit();
}

function testBytesEqual() public {
function testBytesEqual() public view {
bytes memory a = hex"1234";
bytes memory b = hex"1234";
bytes memory c = hex"1235";
Expand All @@ -239,11 +239,32 @@ contract BridgeTest is Test {
assert(!bridge.isBytesEqual_(d, e));
assert(bridge.isBytesEqual_(d, f));

vm.expectRevert();
bridge.isBytesEqual_(a, d);
assertFalse(bridge.isBytesEqual_(a, d));
assertFalse(bridge.isBytesEqual_(a, hex""));
}

vm.expectRevert();
bridge.isBytesEqual_(a, hex"");
function testBytesEqualEdge() public view {
bytes memory a31 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b";
bytes memory b31 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b";
bytes memory c31 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596a";
assert(bridge.isBytesEqual_(a31, b31));
assert(!bridge.isBytesEqual_(a31, c31));

bytes memory a32 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b5c";
bytes memory b32 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b5c";
bytes memory c32 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b5a";
assert(bridge.isBytesEqual_(a32, b32));
assert(!bridge.isBytesEqual_(a32, c32));

bytes memory a33 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b5c1f";
bytes memory b33 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b5c1f";
bytes memory c33 = hex"689059e65a478c636524643c3141f00fe3c27b802580fc12a3da9bc373596b5c1a";
assert(bridge.isBytesEqual_(a33, b33));
assert(!bridge.isBytesEqual_(a33, c33));

assert(!bridge.isBytesEqual_(a31, a32));
assert(!bridge.isBytesEqual_(a31, a33));
assert(!bridge.isBytesEqual_(a32, a33));
}

function testBytesEqualFuzz(bytes memory a, bytes memory b) public view {
Expand Down
2 changes: 1 addition & 1 deletion resources/genesis/bitcoin-regtest/evm.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/genesis/mock-dockerized/evm.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/genesis/mock/evm.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/test-data/demo-tests/bitcoin-regtest/evm.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/test-data/demo-tests/mock/evm.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/test-data/integration-tests/evm.json

Large diffs are not rendered by default.

0 comments on commit 44c10f0

Please sign in to comment.