Submission 01a1bdd5...

ChallengeHex decoder
Submitterzac.creditmint.eth
Submitted at2018-38-09
Gas used39161
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 output) {
        assembly {
            // 0x9000000000000000000000000000000000000000000000000000000000000000 2**255 + 2**252
            // variable declarations:
            // f = size of string in bytes
            // s = size of output in bytes
            // i = calldataload index of next word
            2 0x24 calldataload div         // s   

            0x44                            // i s
            0x40                            // m i s
            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

                0x20 mstore

                4 mload
                6 mload
                8 mload
                10 mload
                12 mload
                14 mload
                16 mload
                18 mload
                20 mload
                22 mload
                24 mload
                26 mload
                28 mload
                30 mload
                32 mload

                48 mstore8
                47 mstore8
                46 mstore8
                45 mstore8
                44 mstore8
                43 mstore8
                42 mstore8
                41 mstore8
                40 mstore8
                39 mstore8
                38 mstore8
                37 mstore8
                36 mstore8
                35 mstore8
                34 mstore8

                33 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
                                    // s
                0x20 0x00 mstore    // s
                dup1 0x20 mstore    // store s at 0x20
                0x40 add            // s+0x40
                0x0000000000000000000000000000000000000000000000000000000000000000
                dup2 mstore         // store 0 at s+0x40

                                    // 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:
                0
                return
        }
    }
}