Submission e6ea0c2e...

ChallengeHex decoder
Submitterhyszeth.eth
Submitted at2018-33-28
Gas used882000
/**
 * 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: Greg Hysen (@hysz)
 * Date: June 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) public pure returns(bytes output) {
        uint j = 0;
        uint inputLen = bytes(input).length;
        if(inputLen == 0) return output;

        output = new bytes(inputLen / 2);
        for(uint i = 0; i != inputLen; i += 2) {
            // Combine left & right into one whole byte
            output[j++] = byte(
                                getHalfOfByte(uint(bytes(input)[i+1])) +
                                getHalfOfByte(uint(bytes(input)[i])) * 16
                              );
        }
    }

    function getHalfOfByte(uint hexLetter) internal pure returns (uint) {
        /*
            [0-9] is 0x30 to 0x39
            [a-f] is 0x41 to 0x46
            [A-F] is 0x61 to 0x66

            We take advantage of these ranges to construct the conversion below.

            #1
                ASCII `0` maps to 48, so `0 % 16` == 0x0, `1 % 16` == 0x1, ...
                ASCII `a` and ASCII `A` map to 65 and 97, respectively; so
                `a % 16` == 0x1 and `A % 16` == 0x1.
                The correct mapping is `a%16 + 9` and `A%16 + 9`.

                * For a-f/A-F we add 9, and for 0-9 we do not.

            #2
                Looking at the binary representations of these character ranges,
                a-f and A-F have a leading `1` (for 64). The range 0-9 does not
                have this. By dividing by 64 we'll shift this MSB bit to equal 1
                for a-f/A-F and 0 for 0-9.

                * We can then multiply this value by 9 to get the correct offset.

	   #3  It's cheaper to & than %, so rather than %16 we &15.

        */
        return (hexLetter/uint(64)) * 9 + hexLetter & 15;
    }


}