Submission f80bb946...

ChallengeHex decoder
Submitterricmoo.firefly.eth
Submitted at2018-21-01
Gas used30654
pragma solidity 0.4.24;

contract HexDecoder {

    function decode(string /* input */) pure public returns(bytes) {
        assembly {

          // WARNING! This is NOT safe. For the purpose of this contest I
          //          am assuming the ABI pointer to the dynamic slot is
          //          32, but that is not, in general, safe to assume
          let offset := 68
          let length := calldataload(36)
          let end := add(68, length)

          // Output length
          length := div(length, 2)

          // Allocate memory for the response
          let output := mload(0x40)
          let outputLength := and(add(length, 95), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)
          let outOffset := add(output, 64)

          // Should do this, to update free-memory pointer, but since we aren't using any Solidity
          // this is safe to leave
          //mstore(0x40, add(output, outputLength))

          // Pointer to the dynamic slot for the bytes
          mstore(output, 0x20)

          // Length of the bytes (half the length)
          mstore(add(output, 32), length)

          let data := calldataload(offset)

          for { } lt(offset, end) { } {

            //data := calldataload(offset)

            // For letters, the 7th bit is high; n0 is 0x90 for letters 0x00 for numbers
            let n0 := and(data, 0x5050505050505050505050505050505050505050505050505050505050505050)
            n0 := add(n0, 0x5050505050505050505050505050505050505050505050505050505050505050)
            n0 := and(n0, 0x9090909090909090909090909090909090909090909090909090909090909090)

            // Move the data over 1 nibble
            data := mul(data, 0x10)

            // Take the lowest nibble from each ascii character (upper nibble since we shifted)
            // 0-9: already the correct value
            // A-F: add 9 to the value to offset A (1) -> 10, etc
            data := and(data, 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0)
            data := add(n0, data)

            // Shift all nibbles over to the left and odd nibbles into their neighbour
            // (odd bytes become junk)
            data := or(data, mul(data, 0x10))

            // Remove the spaces in the output by chunking
            data := and(data, 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00)
            data := or(data, mul(data, 0x100))
            data := and(data, 0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000)
            data := or(data, mul(data, 0x10000))
            data := and(data, 0xffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000)
            data := or(data, mul(data, 0x100000000))
            data := and(data, 0xffffffffffffffff0000000000000000ffffffffffffffff0000000000000000)
            data := or(data, mul(data, 0x10000000000000000))

            mstore(outOffset, data)

            outOffset := add(outOffset, 16)

            offset := add(offset, 32)

            data := calldataload(offset)
          }

          mstore(add(output, add(length, 64)), 0)


          return(output, outputLength)
        }
    }
}