/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: HashCash.cpp Date: 2022-9-18 Author: Reece ***/ #include #include "HashCash.hpp" namespace Aurora::Crypto::HashCash { AUKN_SYM bool CheckSalt(AuUInt64 token, AuUInt8 power, const HashCashAnswer &answer) { for (AU_ITERATE_N(i, 2)) { AuUInt64 uCoefficient {}; AuArray hashBuffer; if (i == 0) { AuHashing::RMD128(AuMemoryViewRead(&token, sizeof(token)), hashBuffer); uCoefficient = answer.y & 0xFFFFFFFF; } else { AuHashing::RMD128(AuMemoryViewRead(&token, sizeof(token)), hashBuffer); AuHashing::RMD128(AuMemoryViewRead(hashBuffer.data(), hashBuffer.size()), hashBuffer); uCoefficient = (answer.y >> 32) & 0xFFFFFFFF; } AuWriteU64LE(hashBuffer.data(), hashBuffer.size() - 8, AuReadU64LE(hashBuffer.data(), hashBuffer.size() - 8) + uCoefficient); AuHashing::RMD128(AuMemoryViewRead(hashBuffer.data(), hashBuffer.size()), hashBuffer); AuUInt8 count {}; AuBitScanForward(count, AuReadU64LE(hashBuffer.data(), 0)); if (count != power) { return false; } } return true; } AUKN_SYM HashCashAnswer FindAnswer(AuUInt64 token, AuUInt8 power) { HashCashAnswer answer {}; AuArray refBuffer; AuArray rollingBuffer; AuArray hashBuffer; for (AU_ITERATE_N(i, 2)) { if (i == 0) { AuHashing::RMD128(AuMemoryViewRead(&token, sizeof(token)), refBuffer); } else { AuHashing::RMD128(AuMemoryViewRead(&token, sizeof(token)), refBuffer); AuHashing::RMD128(AuMemoryViewRead(refBuffer.data(), refBuffer.size()), refBuffer); } AuUInt64 uTicks {}; AuUInt8 count {}; do { rollingBuffer = refBuffer; AuWriteU64LE(rollingBuffer.data(), rollingBuffer.size() - 8, AuReadU64LE(rollingBuffer.data(), rollingBuffer.size() - 8) + (uTicks++)); AuHashing::RMD128(AuMemoryViewRead(rollingBuffer.data(), rollingBuffer.size()), hashBuffer); } while (AuBitScanForward(count, AuReadU64LE(hashBuffer.data(), 0)), count != power); uTicks--; if (i == 0) { answer.y = uTicks; } else { answer.y |= uTicks << 32; } } return answer; } }