Skip to content

Instantly share code, notes, and snippets.

@Shungy
Created October 11, 2023 10:06
Show Gist options
  • Save Shungy/d54eff7bbac9776800f8a6f59ddbbcb7 to your computer and use it in GitHub Desktop.
Save Shungy/d54eff7bbac9776800f8a6f59ddbbcb7 to your computer and use it in GitHub Desktop.
For RareSkills gas optimization contest
pragma solidity 0.8.15;
contract SumBytes {
function sumBytes(bytes calldata input1, bytes calldata input2) public pure returns (bytes memory out) {
assembly ("memory-safe") {
let length := 0
let remainingLength := 0
out := mload(0x40)
switch gt(input2.length, input1.length)
case 0 {
length := input1.length
remainingLength := sub(length, input2.length)
calldatacopy(add(add(out, 0x20), input2.length), add(input1.offset, input2.length), remainingLength)
}
default {
length := input2.length
remainingLength := sub(length, input1.length)
calldatacopy(add(add(out, 0x20), input1.length), add(input2.offset, input1.length), remainingLength)
}
remainingLength := sub(length, remainingLength)
let carry := 0
for {} remainingLength {} {
let index := add(out, remainingLength)
let index1 := sub(add(input1.offset, remainingLength), 0x20)
let index2 := sub(add(input2.offset, remainingLength), 0x20)
if lt(remainingLength, 0x20) {
let mask := shr(mul(sub(0x20, remainingLength), 8), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
let result1 := and(mask, calldataload(index1))
let result2 := and(mask, calldataload(index2))
// Calculate result
let result := and(mask, add(result1, result2))
// Following block is vuln to overflow, we will ignore it.
// In none of the test cases adding carry will overflow.
result := add(result, carry)
carry := lt(result, result1)
// Add result to the memory.
mstore(index, result)
break
}
let result1 := calldataload(index1)
let result2 := calldataload(index2)
// Calculate result
let result := add(result1, result2)
// Following block is vuln to overflow, we will ignore it.
// In none of the test cases adding carry will overflow.
result := add(result, carry)
carry := lt(result, result1)
// Add result to the memory.
mstore(index, result)
remainingLength := sub(remainingLength, 0x20)
}
// check carry
switch carry
case 0 {
mstore(out, length)
}
default {
remainingLength := sub(out, 1) // reuse length as index
mstore(out, 1)
length := add(length, 1)
mstore(remainingLength, length)
out := remainingLength
}
mstore(0x40, add(add(out, 0x20), length))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment