Challenge Hex decoder hyszeth.eth 2018-35-13 911874
``````/**
* This file is part of the 1st Solidity Gas Golfing Contest.
*
* 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;

// Assumption: all competition inputs are multiples of 2 (this assumption saves gas)
output = new bytes(inputLen / 2); // +1 because we need to round up
inputLen -= 1;
for(uint i = 0; i < inputLen; i += 2) {
// Combine left & right into one whole byte
output[j++] = byte(
getHalfOfByte(uint8(bytes(input)[i+1])) +
getHalfOfByte(uint8(bytes(input)[i])) * 16
);
}
}

function getHalfOfByte(uint8 hexLetter) internal pure returns (uint8) {
/*
[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/uint8(64)) * 9 + hexLetter & 15;
}

}

``````