Full DAG size, epoch scaling etc.
This commit is contained in:
@@ -29,32 +29,31 @@ extern bool minicoin_autolykos2_ref_check_target(
|
||||
#endif
|
||||
|
||||
static bool Autolykos2_FallbackHash(
|
||||
const Autolykos2Context* ctx,
|
||||
const uint8_t seed32[32],
|
||||
const uint8_t* message,
|
||||
size_t messageLen,
|
||||
uint64_t nonce,
|
||||
uint32_t height,
|
||||
uint64_t height,
|
||||
uint8_t outHash[32]
|
||||
) {
|
||||
if (!seed32 || !outHash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t nonceBytes[8];
|
||||
uint8_t heightBytes[4];
|
||||
uint8_t heightBytes[8];
|
||||
memcpy(nonceBytes, &nonce, sizeof(nonceBytes));
|
||||
memcpy(heightBytes, &height, sizeof(heightBytes));
|
||||
|
||||
size_t dagChunkLen = 0;
|
||||
const uint8_t* dagChunk = NULL;
|
||||
if (ctx && ctx->dag.buf && ctx->dag.len > 0) {
|
||||
dagChunk = ctx->dag.buf;
|
||||
dagChunkLen = ctx->dag.len > 64 ? 64 : ctx->dag.len;
|
||||
}
|
||||
|
||||
const size_t totalLen = messageLen + sizeof(nonceBytes) + sizeof(heightBytes) + dagChunkLen;
|
||||
const size_t totalLen = 32 + messageLen + sizeof(nonceBytes) + sizeof(heightBytes);
|
||||
uint8_t* material = (uint8_t*)malloc(totalLen == 0 ? 1 : totalLen);
|
||||
if (!material) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t off = 0;
|
||||
memcpy(material + off, seed32, 32);
|
||||
off += 32;
|
||||
if (messageLen > 0) {
|
||||
memcpy(material + off, message, messageLen);
|
||||
off += messageLen;
|
||||
@@ -62,10 +61,6 @@ static bool Autolykos2_FallbackHash(
|
||||
memcpy(material + off, nonceBytes, sizeof(nonceBytes));
|
||||
off += sizeof(nonceBytes);
|
||||
memcpy(material + off, heightBytes, sizeof(heightBytes));
|
||||
off += sizeof(heightBytes);
|
||||
if (dagChunkLen > 0) {
|
||||
memcpy(material + off, dagChunk, dagChunkLen);
|
||||
}
|
||||
|
||||
const bool ok = Blake2b_Hash(material, totalLen, outHash, 32);
|
||||
free(material);
|
||||
@@ -80,6 +75,172 @@ static int Cmp256BE(const uint8_t a[32], const uint8_t b[32]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void WriteU64LE(uint64_t v, uint8_t out[8]) {
|
||||
out[0] = (uint8_t)(v & 0xffu);
|
||||
out[1] = (uint8_t)((v >> 8) & 0xffu);
|
||||
out[2] = (uint8_t)((v >> 16) & 0xffu);
|
||||
out[3] = (uint8_t)((v >> 24) & 0xffu);
|
||||
out[4] = (uint8_t)((v >> 32) & 0xffu);
|
||||
out[5] = (uint8_t)((v >> 40) & 0xffu);
|
||||
out[6] = (uint8_t)((v >> 48) & 0xffu);
|
||||
out[7] = (uint8_t)((v >> 56) & 0xffu);
|
||||
}
|
||||
|
||||
static void WriteU32LE(uint32_t v, uint8_t out[4]) {
|
||||
out[0] = (uint8_t)(v & 0xffu);
|
||||
out[1] = (uint8_t)((v >> 8) & 0xffu);
|
||||
out[2] = (uint8_t)((v >> 16) & 0xffu);
|
||||
out[3] = (uint8_t)((v >> 24) & 0xffu);
|
||||
}
|
||||
|
||||
static bool DeriveSeedFromMessage(const uint8_t* message, size_t messageLen, uint8_t outSeed[32]) {
|
||||
if (!message || !outSeed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Blake2b_Hash(message, messageLen, outSeed, 32);
|
||||
}
|
||||
|
||||
static bool ComputeLaneIndex(
|
||||
const uint8_t seed32[32],
|
||||
uint64_t nonce,
|
||||
uint64_t height,
|
||||
uint32_t round,
|
||||
uint32_t laneCount,
|
||||
uint32_t* outLane
|
||||
) {
|
||||
if (!seed32 || !outLane || laneCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t input[32 + 8 + 8 + 4];
|
||||
uint8_t digest[32];
|
||||
uint8_t nonceBytes[8];
|
||||
uint8_t heightBytes[8];
|
||||
uint8_t roundBytes[4];
|
||||
|
||||
WriteU64LE(nonce, nonceBytes);
|
||||
WriteU64LE(height, heightBytes);
|
||||
WriteU32LE(round, roundBytes);
|
||||
|
||||
memcpy(input, seed32, 32);
|
||||
memcpy(input + 32, nonceBytes, sizeof(nonceBytes));
|
||||
memcpy(input + 40, heightBytes, sizeof(heightBytes));
|
||||
memcpy(input + 48, roundBytes, sizeof(roundBytes));
|
||||
|
||||
if (!Blake2b_Hash(input, sizeof(input), digest, sizeof(digest))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t raw =
|
||||
((uint32_t)digest[0]) |
|
||||
((uint32_t)digest[1] << 8) |
|
||||
((uint32_t)digest[2] << 16) |
|
||||
((uint32_t)digest[3] << 24);
|
||||
*outLane = raw % laneCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReadDagLaneFromContext(const Autolykos2Context* ctx, uint32_t laneIndex, uint8_t outLane[32]) {
|
||||
if (!ctx || !ctx->dag.buf || !outLane) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t offset = (size_t)laneIndex * 32u;
|
||||
if (ctx->dag.len < offset + 32u) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(outLane, ctx->dag.buf + offset, 32);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReadDagLaneFromSeed(const uint8_t seed32[32], uint32_t laneIndex, uint8_t outLane[32]) {
|
||||
if (!seed32 || !outLane) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t counter = (uint64_t)laneIndex / 2u;
|
||||
const bool upperHalf = (laneIndex & 1u) != 0u;
|
||||
uint8_t input[32 + 8];
|
||||
uint8_t digest[64];
|
||||
uint8_t counterBytes[8];
|
||||
|
||||
WriteU64LE(counter, counterBytes);
|
||||
memcpy(input, seed32, 32);
|
||||
memcpy(input + 32, counterBytes, sizeof(counterBytes));
|
||||
|
||||
if (!Blake2b_Hash(input, sizeof(input), digest, sizeof(digest))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(outLane, digest + (upperHalf ? 32 : 0), 32);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Autolykos2_HashCore(
|
||||
const uint8_t seed32[32],
|
||||
const uint8_t* message,
|
||||
size_t messageLen,
|
||||
uint64_t nonce,
|
||||
uint64_t height,
|
||||
uint32_t laneCount,
|
||||
const Autolykos2Context* ctx,
|
||||
bool useContextDag,
|
||||
uint8_t outHash[32]
|
||||
) {
|
||||
if (!seed32 || !message || !outHash || laneCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t acc[32];
|
||||
memset(acc, 0, sizeof(acc));
|
||||
|
||||
for (uint32_t round = 0; round < 32; ++round) {
|
||||
uint32_t laneIndex = 0;
|
||||
uint8_t lane[32];
|
||||
|
||||
if (!ComputeLaneIndex(seed32, nonce, height, round, laneCount, &laneIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (useContextDag) {
|
||||
if (!ReadDagLaneFromContext(ctx, laneIndex, lane)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!ReadDagLaneFromSeed(seed32, laneIndex, lane)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
acc[i] ^= lane[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t baseHash[32];
|
||||
uint8_t accHash[32];
|
||||
if (!Autolykos2_FallbackHash(seed32, message, messageLen, nonce, height, baseHash)) {
|
||||
return false;
|
||||
}
|
||||
if (!Blake2b_Hash(acc, sizeof(acc), accHash, sizeof(accHash))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t finalInput[32 + 32 + 8 + 8];
|
||||
uint8_t nonceBytes[8];
|
||||
uint8_t heightBytes[8];
|
||||
WriteU64LE(nonce, nonceBytes);
|
||||
WriteU64LE(height, heightBytes);
|
||||
|
||||
memcpy(finalInput, baseHash, 32);
|
||||
memcpy(finalInput + 32, accHash, 32);
|
||||
memcpy(finalInput + 64, nonceBytes, 8);
|
||||
memcpy(finalInput + 72, heightBytes, 8);
|
||||
return Blake2b_Hash(finalInput, sizeof(finalInput), outHash, 32);
|
||||
}
|
||||
|
||||
Autolykos2Context* Autolykos2_Create(void) {
|
||||
Autolykos2Context* ctx = (Autolykos2Context*)calloc(1, sizeof(Autolykos2Context));
|
||||
if (!ctx) {
|
||||
@@ -144,6 +305,38 @@ bool Autolykos2_DagAppend(Autolykos2Context* ctx, const uint8_t* data, size_t le
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Autolykos2_DagGenerate(Autolykos2Context* ctx, const uint8_t seed32[32]) {
|
||||
if (!ctx || !seed32 || !ctx->dag.buf || ctx->dag.cap == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t input[32 + 8];
|
||||
uint8_t digest[64];
|
||||
size_t offset = 0;
|
||||
uint64_t counter = 0;
|
||||
|
||||
while (offset < ctx->dag.cap) {
|
||||
WriteU64LE(counter, input + 32);
|
||||
memcpy(input, seed32, 32);
|
||||
|
||||
if (!Blake2b_Hash(input, sizeof(input), digest, sizeof(digest))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t chunk = ctx->dag.cap - offset;
|
||||
if (chunk > sizeof(digest)) {
|
||||
chunk = sizeof(digest);
|
||||
}
|
||||
|
||||
memcpy(ctx->dag.buf + offset, digest, chunk);
|
||||
offset += chunk;
|
||||
++counter;
|
||||
}
|
||||
|
||||
ctx->dag.len = ctx->dag.cap;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Autolykos2_DagClear(Autolykos2Context* ctx) {
|
||||
if (!ctx || !ctx->dag.buf) {
|
||||
return;
|
||||
@@ -161,21 +354,75 @@ bool Autolykos2_Hash(
|
||||
const uint8_t* message,
|
||||
size_t messageLen,
|
||||
uint64_t nonce,
|
||||
uint32_t height,
|
||||
uint64_t height,
|
||||
uint8_t outHash[32]
|
||||
) {
|
||||
if (!ctx || !message || !outHash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Autolykos2_FallbackHash(ctx, message, messageLen, nonce, height, outHash);
|
||||
if (!ctx->dag.buf || ctx->dag.len < 32 || (ctx->dag.len % 32) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t seed32[32];
|
||||
if (!DeriveSeedFromMessage(message, messageLen, seed32)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t laneCount64 = ctx->dag.len / 32u;
|
||||
if (laneCount64 == 0 || laneCount64 > UINT32_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Autolykos2_HashCore(
|
||||
seed32,
|
||||
message,
|
||||
messageLen,
|
||||
nonce,
|
||||
height,
|
||||
(uint32_t)laneCount64,
|
||||
ctx,
|
||||
true,
|
||||
outHash
|
||||
);
|
||||
}
|
||||
|
||||
bool Autolykos2_LightHash(const uint8_t* seed, blockchain_t* chain, uint64_t nonce, uint8_t* out) {
|
||||
if (!seed || !chain || !out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t height = (uint64_t)Chain_Size(chain);
|
||||
const size_t dagBytes = CalculateTargetDAGSize(chain);
|
||||
if (dagBytes < 32 || (dagBytes % 32) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t laneCount64 = dagBytes / 32u;
|
||||
if (laneCount64 == 0 || laneCount64 > UINT32_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Light path derives the needed DAG lanes from seed on-demand, no large DAG allocation required.
|
||||
return Autolykos2_HashCore(
|
||||
seed,
|
||||
seed,
|
||||
32,
|
||||
nonce,
|
||||
height,
|
||||
(uint32_t)laneCount64,
|
||||
NULL,
|
||||
false,
|
||||
out
|
||||
);
|
||||
}
|
||||
|
||||
bool Autolykos2_CheckTarget(
|
||||
Autolykos2Context* ctx,
|
||||
const uint8_t message32[32],
|
||||
uint64_t nonce,
|
||||
uint32_t height,
|
||||
uint64_t height,
|
||||
const uint8_t target32[32],
|
||||
uint8_t outHash[32]
|
||||
) {
|
||||
@@ -186,14 +433,14 @@ bool Autolykos2_CheckTarget(
|
||||
#ifdef MINICOIN_AUTOLYKOS2_REF_AVAILABLE
|
||||
if (ctx->backend) {
|
||||
const bool ok = minicoin_autolykos2_ref_check_target(ctx->backend, message32, nonce, height, target32);
|
||||
if (Autolykos2_FallbackHash(ctx, message32, 32, nonce, height, outHash)) {
|
||||
if (Autolykos2_Hash(ctx, message32, 32, nonce, height, outHash)) {
|
||||
return ok;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Autolykos2_FallbackHash(ctx, message32, 32, nonce, height, outHash)) {
|
||||
if (!Autolykos2_Hash(ctx, message32, 32, nonce, height, outHash)) {
|
||||
return false;
|
||||
}
|
||||
return Cmp256BE(outHash, target32) <= 0;
|
||||
@@ -202,7 +449,7 @@ bool Autolykos2_CheckTarget(
|
||||
bool Autolykos2_FindNonceSingleCore(
|
||||
Autolykos2Context* ctx,
|
||||
const uint8_t message32[32],
|
||||
uint32_t height,
|
||||
uint64_t height,
|
||||
const uint8_t target32[32],
|
||||
uint64_t startNonce,
|
||||
uint64_t maxIterations,
|
||||
|
||||
Reference in New Issue
Block a user