Submission 38ec354e...

ChallengeHex decoder
Submitterzac.creditmint.eth
Submitted at2018-02-10
Gas used39242
pragma solidity ^0.4.23;

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) external view returns(bytes) {
        assembly {
            // 0x9000000000000000000000000000000000000000000000000000000000000000 2**255 + 2**252
            // variable declarations:
            // w = calldata word
            // s = size of output in bytes
            // i = calldataload index of next word
            2 0x24 calldataload div         // s   

            add(target, 0x40)
            0x44                            // i s
            dup2
            loop_start:
                // load next word of calldata
                dup2 calldataload               // w m i s

                // 0-9 = 0x30 - 0x39
                // A-F = 0x41 - 0x46
                // a-f = 0x61 - 0x66
                // if a byte = A-F || a-F, 5th bit will be 0
                // if a byte = 0-9, 5th bit will be 1

                0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
                // set all bits except 5th to 1, then invert
                dup2 0xEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEF or not
                // multiply by 2**255 + 2**252, trigger integer overflow so that
                // every 5th bit becomes every (4th + 1st) bit
      
                0x9000000000000000000000000000000000000000000000000000000000000000
                mulmod
                // combine back into w
                add
                // mask out the top 4 bits of every byte
                0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F and
                16 dup2 div or

                dup1
                target mstore

                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
                pc mload
target:

                14 mstore8
                13 mstore8
                12 mstore8
                11 mstore8
                10 mstore8
                9 mstore8
                8 mstore8
                7 mstore8
                6 mstore8
                5 mstore8
                4 mstore8
                3 mstore8
                2 mstore8
                1 mstore8
                0 mstore8
                15 mstore8
                0 mload     // w m i s
                dup2 mstore // m i s
                0x10 add    // m' i s
                swap1 0x20 add // i' m' s
                swap1       // m' i' s
                dup2 calldatasize gt
                loop_start jumpi

                // end of the loop, we need to exit
                pop pop
  
                0x20 target mstore    // m s
                dup2 0x20 target add mstore    // m, store s at 0x20
                add            // add m, s
                0x0000000000000000000000000000000000000000000000000000000000000000
                dup2 mstore         // store 0 at s+0x40


                dup1 0x1f and iszero // jump to skip if no bits below 32
                skip jumpi

                // if there are bits below 32, add 32
                0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 and 0x20 or

                skip:
                target
                return
        }
    }
}