Musk
November 21, 2021, 2:48pm
1
Hi there does anyone how to cast a result of a keccak256/sha256, which returns a bytes32 into a string in Solidity? This doesn't seem to work in comparison to normal bytes32 objects and throws a failed to decode output
error every time.
Here is the code below:
function getHash(uint256 _id) external view returns (string memory) {
return string(abi.encodePacked(keccak256(abi.encodePacked(_id, "value"))));
}
The error:
"error": "Failed to decode output: null: invalid codepoint at offset 0;
unexpected continuation byte (argument=\"bytes\",
value=Uint8Array(0x8bb170e451ca7e22248c3383ea823c551dfb51469997174dd0ab7034be4877bb),
code=INVALID_ARGUMENT, version=strings/5.4.0)"
1 Like
Musk
November 21, 2021, 3:38pm
2
Found the solution, pass the result of the hash into this function toHex(bytes32 _hash)
Source: https://stackoverflow.com/questions/67893318/solidity-how-to-represent-bytes32-as-string
function toHex(bytes32 data) public pure returns (string memory) {
return string(abi.encodePacked("0x", toHex16(bytes16(data)), toHex16(bytes16(data << 128))));
}
function toHex16(bytes16 data) internal pure returns (bytes32 result) {
result =
(bytes32(data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000) |
((bytes32(data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64);
result =
(result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000) |
((result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32);
result =
(result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000) |
((result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16);
result =
(result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000) |
((result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8);
result =
((result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4) |
((result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8);
result = bytes32(
0x3030303030303030303030303030303030303030303030303030303030303030 +
uint256(result) +
(((uint256(result) + 0x0606060606060606060606060606060606060606060606060606060606060606) >> 4) &
0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) *
7
);
}
1 Like
frangio
November 24, 2021, 1:30am
3
Note that OpenZeppelin Contracts includes a Strings.toHex
utility function as well.
Musk
November 24, 2021, 2:32pm
4
Right but that does not take a bytes
as an input, only uint256
which is not what the result of a keccak256/sha256
returns.
You can try this:
function bytes32ToString(bytes32 _b) external pure returns (string memory) {
return string(abi.encodePacked(_b));
}
Musk
November 24, 2021, 4:48pm
6
This won't work for a result of a hashing function.
frangio
November 25, 2021, 7:22pm
7
You're right. My bad!
For the record, it's still possible to use our library with bytes32 with a little workaround, by casting bytes32 to uint256:
Strings.toHexString(uint256(keccak256(...)), 32);
1 Like
trogg
June 11, 2022, 4:49pm
9
if only that worked. there would be no need for this question
trogg
June 11, 2022, 4:51pm
10
what's the reason this doesn't work for a hash?
MToken
July 15, 2022, 2:17pm
11
Because it is "one-way". Keccak creates a unique hash out of an input... if you could decode it just back there would be no "private" keys.
trogg
August 16, 2022, 7:00pm
12
well, not quite ... hashing isn't the same as encryption, but the question was never about trying to reverse a hash. It was about turning the hash output from bytes32 to a string representation of the same, and so you could do something like print it out with hardhat's console.log() or some other thing that you can do with a string but can't with bytes32
1 Like
Musk
August 18, 2022, 6:52am
13
Yes exactly. The solution I posted was the only way to resolve this.