How to convert/cut uint256_t to uint8_t[ ]

Viewed 262

I got one library that uses uint256_t to represent a hash, and another library that uses uint8_t array for this.

I guess there should be a way to cut/convert this uint256_t into an uint8_t[32] somehow.

However, I couldn't find yet how that could be easily converted.

3 Answers

Use memcpy.

You have two unrelated types, but you know that the binary representation of the hash is identical for both. The safest way to convert between the two is via memcpy.

uint256_t source_hash;
// compute source_hash
// [...]

uint8_t dest_hash[32];
std::memcpy(dest_hash, &source_hash, 32);

Note that this only works if the binary representations are indeed the same. If for instance, library A stores the hash in big-endian and library B stores it in little-endian, you need a more complex conversion. While in the case of hashes, it is very likely that the binary representation is indeed identical, be sure to double check that before writing a memcpy based conversion.

C++20 added the std::bit_cast, which can also be used for conversions like this, and will in all likelihood generate identical machine code to a solution based on calling memcpy. If your compiler already supports this, you may prefer bit_cast as it is syntactically similar to the built-in C++ casts.

I just tried out the following and that seem to have worked fine. However, I'm not sure of the possible implications.

uint256_t msg = 1040449494439944;
uint8_t* hash =  (uint8_t*) &msg;
cout << sizeof(hash) << endl;

In C++20 we will have std::bit_cast (https://en.cppreference.com/w/cpp/numeric/bit_cast) for this. Until then the standard and defined way would be to use std::memcpy:

uint256_t msg = 1040449494439944;
uint8_t hash[32] = {};
std::memcpy(hash, &msg, sizeof(msg));

In depth explanation of why c-cast that ultimately calls reinterpret_cast in this case is bad by Jason Turner.

Related