Submission eef486bb...

ChallengeHex decoder
Submitterricmoo.firefly.eth
Submitted at
Gas used71892
/**
 * 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 {

    /**
     * @dev Decodes a hex-encoded input string, returning it in binary.
     *
     * Input strings may be of any length, but will always be a multiple of two
     * bytes long, and will not contain any non-hexadecimal characters.
     *
     * @param input The hex-encoded input.
     * @return The decoded output.
     */

    function decode(string input) pure public returns(bytes output) {
        output = bytes(input);

        assembly {
          let offset := add(output, 32)
          let length := mload(output)
          let end := add(offset, length)

          // The output length is half the input length
          mstore(output, div(length, 2))

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

            let data := mload(offset)

            // For letters, the 7th bit is high; create 9 if set
            let n0 := and(0x4040404040404040404040404040404040404040404040404040404040404040, data)
            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(0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f, data)
            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, 16), mul(data, 256))

            mstore8(outOffset, byte(0, data))
            mstore8(add(outOffset, 1), byte(2, data))
            mstore8(add(outOffset, 2), byte(4, data))
            mstore8(add(outOffset, 3), byte(6, data))
            mstore8(add(outOffset, 4), byte(8, data))
            mstore8(add(outOffset, 5), byte(10, data))
            mstore8(add(outOffset, 6), byte(12, data))
            mstore8(add(outOffset, 7), byte(14, data))
            mstore8(add(outOffset, 8), byte(16, data))
            mstore8(add(outOffset, 9), byte(18, data))
            mstore8(add(outOffset, 10), byte(20, data))
            mstore8(add(outOffset, 11), byte(22, data))
            mstore8(add(outOffset, 12), byte(24, data))
            mstore8(add(outOffset, 13), byte(26, data))
            mstore8(add(outOffset, 14), byte(28, data))
            mstore8(add(outOffset, 15), byte(30, data))

            outOffset := add(outOffset, 16)

            offset := add(offset, 0x20)
          }
        }
    }
}