"Is there a problem with using int64_t instead of uint64_t here?
If all the bit-shifted values stay below 2^63, there is generally no problem with using a signed 64-bit integer. For your usage (shifting up to 1LL << 52), you're well within the range of int64_t, so you shouldn't encounter overflows or negative values.
If you conceptually treat these bit patterns as pure bitmasks, some developers prefer using uint64_t to make the signed/unsigned intent explicit.
"Is there a more idiomatic or correct way to write code like this?"
As is, the code works.