MinecraftConsoles/Minecraft.World/UUID.cpp
2026-04-04 02:17:59 -04:00

146 lines
4 KiB
C++

#include "stdafx.h"
#include "UUID.h"
#include "Random.h"
#include <cstring>
static void sha1_block(uint32_t h[5], const uint8_t block[64])
{
uint32_t w[80];
for (int i = 0; i < 16; i++)
w[i] = (block[i * 4] << 24) | (block[i * 4 + 1] << 16) | (block[i * 4 + 2] << 8) | block[i * 4 + 3];
for (int i = 16; i < 80; i++) {
uint32_t x = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
w[i] = (x << 1) | (x >> 31);
}
uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4];
for (int i = 0; i < 80; i++) {
uint32_t f, k;
if (i < 20) { f = (b & c) | (~b & d); k = 0x5A827999; }
else if (i < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; }
else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; }
else { f = b ^ c ^ d; k = 0xCA62C1D6; }
uint32_t tmp = ((a << 5) | (a >> 27)) + f + e + k + w[i];
e = d; d = c; c = (b << 30) | (b >> 2); b = a; a = tmp;
}
h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e;
}
static void sha1(const uint8_t* data, size_t len, uint8_t out[20])
{
uint32_t h[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
uint64_t bitLen = len * 8;
size_t fullBlocks = len / 64;
for (size_t blk = 0; blk < fullBlocks; blk++)
sha1_block(h, data + blk * 64);
uint8_t tail[128] = {};
size_t rem = len - fullBlocks * 64;
if (rem) memcpy(tail, data + fullBlocks * 64, rem);
tail[rem] = 0x80;
size_t tailLen = (rem < 56) ? 64 : 128;
for (int i = 0; i < 8; i++)
tail[tailLen - 1 - i] = (uint8_t)(bitLen >> (i * 8));
for (size_t off = 0; off < tailLen; off += 64)
sha1_block(h, tail + off);
for (int i = 0; i < 5; i++) {
out[i * 4] = (uint8_t)(h[i] >> 24);
out[i * 4 + 1] = (uint8_t)(h[i] >> 16);
out[i * 4 + 2] = (uint8_t)(h[i] >> 8);
out[i * 4 + 3] = (uint8_t)(h[i]);
}
}
static constexpr char HEX[] = "0123456789abcdef";
static constexpr uint8_t hexVal(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return 10 + c - 'a';
if (c >= 'A' && c <= 'F') return 10 + c - 'A';
return 0;
}
void GameUUID::toBytes(uint8_t out[16]) const
{
for (int i = 7; i >= 0; i--) out[7 - i] = (uint8_t)(msb >> (i * 8));
for (int i = 7; i >= 0; i--) out[15 - i] = (uint8_t)(lsb >> (i * 8));
}
GameUUID GameUUID::fromBytes(const uint8_t b[16])
{
GameUUID u;
for (int i = 0; i < 8; i++) u.msb = (u.msb << 8) | b[i];
for (int i = 0; i < 8; i++) u.lsb = (u.lsb << 8) | b[8 + i];
return u;
}
std::string GameUUID::toString() const
{
uint8_t b[16];
toBytes(b);
char buf[37];
int p = 0;
for (int i = 0; i < 16; i++) {
if (i == 4 || i == 6 || i == 8 || i == 10) buf[p++] = '-';
buf[p++] = HEX[b[i] >> 4];
buf[p++] = HEX[b[i] & 0xf];
}
buf[p] = '\0';
return buf;
}
std::wstring GameUUID::toWString() const
{
std::string s = toString();
return { s.begin(), s.end() };
}
GameUUID GameUUID::fromString(const std::string& s)
{
uint8_t b[16] = {};
int bi = 0;
for (size_t i = 0; i < s.size() && bi < 16; i++) {
if (s[i] == '-') continue;
if (i + 1 >= s.size()) break;
b[bi++] = (hexVal(s[i]) << 4) | hexVal(s[i + 1]);
i++;
}
return fromBytes(b);
}
GameUUID GameUUID::fromWString(const std::wstring& s)
{
return fromString({ s.begin(), s.end() });
}
GameUUID GameUUID::v4(uint64_t high, uint64_t low)
{
return { (high & ~0xF000ULL) | 0x4000ULL, (low & ~0xC000000000000000ULL) | 0x8000000000000000ULL };
}
GameUUID GameUUID::v5(const GameUUID& ns, const std::string& name)
{
uint8_t input[256];
ns.toBytes(input);
size_t total = 16 + name.size();
// names over 240 chars would be insane but just in case
if (name.size() <= sizeof(input) - 16)
memcpy(input + 16, name.data(), name.size());
uint8_t hash[20];
sha1(input, total, hash);
GameUUID u = fromBytes(hash);
u.msb = (u.msb & ~0xF000ULL) | 0x5000ULL;
u.lsb = (u.lsb & ~0xC000000000000000ULL) | 0x8000000000000000ULL;
return u;
}
GameUUID GameUUID::fromXuid(uint64_t xuid)
{
return v5(MCCONSOLES_NAMESPACE_UUID, std::to_string(xuid));
}
GameUUID GameUUID::random()
{
Random r;
return v4(r.nextLong(), r.nextLong());
}