Submission 6b087e48...

ChallengeHex decoder
Submitterricmoo.firefly.eth
Submitted at2018-16-28
Gas used36314
/**
 * This file is part of the 1st Solidity Gas Golfing Contest.
 *
 * This work is licensed under Creative Commons Attribution ShareAlike 3.0.
 * https://creativecommons.org/licenses/by-sa/3.0/
 *
 * Author: Richard Moore <[email protected]>
 * Date: May 23, 2018
 */


pragma solidity 0.4.24;

contract HexDecoder {

    function decode(string /* input */) pure public returns(bytes) {
        assembly {

          // WARNING! This is NOT safe. For the purpose of this contest I
          //          I a assuming the ABI pointer to the dynamic slot is
          //          32, but that is not, in general, safe to assume
          let offset := 68
          let length := calldataload(36)
          let end := add(68, length)

          // Output length
          length := div(length, 2)

          // Allocate memory for the response
          let output := mload(0x40)
          let outputLength := and(add(length, 95), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)
          mstore(0x40, add(output, outputLength))

          // Pointer to the dynamic slot for the bytes
          mstore(output, 0x20)

          // Length of the bytes (half the length
          mstore(add(output, 32), length)

          let outOffset := add(output, 64)
          for { } lt(offset, end) { } {

            let data := calldataload(offset)

            // For letters, the 7th bit is high; create 9 if set
            let n0 := and(data, 0x4040404040404040404040404040404040404040404040404040404040404040)
            n0 := or(div(n0, 8), div(n0, 64))

            // Take the lowest nibble from each ascii character
            // 0-9: already the correct value
            // A-F: add 9 to the value to offset A (1) -> 10, etc
            data := and(data, 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f)
            data := add(n0, data)

            // Shift all nibbles over to the left and odd nibbles into their neighbour
            // (odd bytes become junk)
            data := or(mul(data, 0x10), mul(data, 0x100))

            // Remove the spaces in the output by chunking
            data := and(data, 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00)
            data := or(data, mul(data, 0x100))
            data := and(data, 0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000)
            data := or(data, mul(data, 0x10000))
            data := and(data, 0xffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000)
            data := or(data, mul(data, 0x100000000))
            data := and(data, 0xffffffffffffffff0000000000000000ffffffffffffffff0000000000000000)
            data := or(data, mul(data, 0x10000000000000000))

            mstore(outOffset, data)

            outOffset := add(outOffset, 16)

            offset := add(offset, 0x20)
          }

          return(output, outputLength)
        }
    }
}