Submission 8f4762e9...

ChallengeHex decoder
Submitterwicketh.eth
Submitted at2018-38-26
Gas used60323
/**
 * 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/
 */

pragma solidity 0.4.24;

// 0  0011 0000 -> 0000
// 1  0011 0001 -> 0001
// 2  0011 0010 -> 0010
// 3  0011 0011 -> 0011
// 4  0011 0100 -> 0100
// 5  0011 0101 -> 0101
// 6  0011 0110 -> 0110
// 7  0011 0111 -> 0111
// 8  0011 1000 -> 1000
// 9  0011 1001 -> 1001
// a  0110 0001 -> 1010
// b  0110 0010 -> 1011
// c  0110 0011 -> 1100
// d  0110 0100 -> 1101
// e  0110 0101 -> 1110
// f  0110 0110 -> 1111
// A  0100 0001 -> 1010
// B  0100 0010 -> 1011
// C  0100 0011 -> 1100
// D  0100 0100 -> 1101
// E  0100 0101 -> 1110
// F  0100 0110 -> 1111

contract HexDecoder {
    
    uint256 constant lowNibs = 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F;
    uint256 constant bit1 = 0x0101010101010101010101010101010101010101010101010101010101010101;
    uint256 constant byten1 = 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF;
    uint256 constant byten2 = 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF;
    uint256 constant byten3 = 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF;
    uint256 constant byten4 = 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF;
    uint256 constant byten5 = 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
    
    uint256 constant s =  0x0000000000000000000000000000000100000000000000000000000000000000;
    
    uint256 constant f1 = 0x11;
    uint256 constant f2 = 0x101;
    uint256 constant f3 = 0x10001;
    uint256 constant f4 = 0x100000001;
    uint256 constant f5 = 0x10000000000000001;

    uint256 constant s1 = 0x10;
    uint256 constant s2 = 0x100;
    uint256 constant s3 = 0x10000;
    uint256 constant s4 = 0x100000000;
    uint256 constant s5 = 0x10000000000000000;

    
    function decode(string input)
        public pure
        returns(bytes output)
    {
        uint256 ol = bytes(input).length / 2;
        output = new bytes(ol);
        
        for(uint i = 0; i < ol; i += 16) {
            
            uint256 a;
            assembly {
                let iaddr := add(mul(i, 2), add(input, 32))
                a := mload(iaddr)
                
                // a = (a & lowNibs) + (9 * ((a / 64) & bit1));
                a := add(and(a,
                    0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F
                ), mul(9, and(div(a, 64),
                    0x0101010101010101010101010101010101010101010101010101010101010101
                )))
                
                // a = ((a * f1) / s1) & byten1;
                a := and(div(mul(a,
                    0x11
                ),
                    0x10
                ),
                    0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF
                )
                
            }
            
            
            // a = ((a * f1) / s1) & byten1;
            a = ((a * f2) / s2) & byten2;
            a = ((a * f3) / s3) & byten3;
            a = ((a * f4) / s4) & byten4;
            a = ((a * f5) / s5) & byten5;
            
            a *= s;
            
            assembly {
                let oaddr := add(i, add(output, 32))
                mstore(oaddr, a)
            }
        }
    }
}

// 0x0A0B0C0D * 0x11 = 
//    0x0A0B0C0D
//   0x0A0B0C0D
//   0x0AABBCCDD 
//    0x0AABBCCD ( / 16)
//    0x00AB00CD ( & 0x00FF00FF )

//    0x00AB00CD 
//  0x00AB00CD00
//  0x00ABABCDCD (* 0x101 )
//    0x00ABABCD (/ 256)
//    0x0000ABCD (& 0x0000FFFF )

// 0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF