igneum/proto-cuda/packs-ca3-shadow/sh256x40/memhard.h
igneum-labs 51dba1ce76 Counter ASIC 3.0 item 8: the latency-shadow knob (LoadClass +sh<S>x<R>), its packs and the PC 2 playbook
A shadow block of S ALU instructions run R times at the end of every iteration, drawn from the program stream after
the 64 base instructions, behind LoadClass::shadow: v2 and v3 draw nothing and emit nothing (the pinned packs are
byte-identical, cargo test 54 + 4 + 19 + 7 green). The interpreter, the three kernel dialects (both kernels each),
program.h and program.json carry it; the acceptance rule interprets the base program only. Packs for seed
igneum-genesis over class mx8 at 4,096 to 180,224 shadow instructions per hash (proto-cuda/packs-ca3-shadow), and
the PC 2 bench playbook tools/ca3-shadow/pc2-shadow-bench.ps1 (passes the publisher's three checks).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 07:58:35 +00:00

109 lines
5.8 KiB
C++

// Generated by igneum-pow export (generator v2) for seed "igneum-genesis". Do not edit by hand.
// Memory-hard dataset core, the same text that the Mac's Metal kernels and CPU verifier were checked against.
// Included by kernel.cu (device), host.cu (host reference) and proto-opencl/host.c (C99 host reference).
// See proto-metal/MEMHARD.md for the construction. kernel.cl carries the same text in OpenCL C.
#pragma once
#ifdef __cplusplus
#include <cstdint>
#else
#include <stdint.h>
#endif
#if defined(__CUDACC__)
#define IGNEUM_HD __host__ __device__ __forceinline__
#elif defined(_MSC_VER) && !defined(__cplusplus)
#define IGNEUM_HD static __inline
#else
#define IGNEUM_HD static inline
#endif
// Memory-hard dataset core (MEMHARD.md). Cache: 2^26 words in 2^16 segments of 64 chained ChaCha12 lines.
// Item: 8 rounds of 8 x seed-parameterised mixer + one 64-byte cache read, then 8 x final mixer (class v3, mixer multiplier 8,
// docs/plans/mixer-x4.md: the round key of application j of round r is 0x9E3779B9 * (r * m + j + 1)). All parameters are literals.
#define MH_CACHE_LINE_MASK 0x003fffffu
#define MH_SEGMENT_LINES 64u
#define MH_QR(a, b, c, d, r1, r2, r3, r4) { a += b; d ^= a; d = mh_rotl(d, r1); c += d; b ^= c; b = mh_rotl(b, r2); a += b; d ^= a; d = mh_rotl(d, r3); c += d; b ^= c; b = mh_rotl(b, r4); }
IGNEUM_HD uint32_t mh_rotl(uint32_t x, uint32_t n) { return (x << n) | (x >> (32u - n)); } // n in 1..31 at every call site
// y = ChaCha12 core(x) + x
IGNEUM_HD void mh_chacha_block(const uint32_t* x, uint32_t* y) {
for (uint32_t i = 0u; i < 16u; ++i) y[i] = x[i];
for (uint32_t r = 0u; r < 6u; ++r) {
MH_QR(y[0], y[4], y[8], y[12], 16u, 12u, 8u, 7u) MH_QR(y[1], y[5], y[9], y[13], 16u, 12u, 8u, 7u)
MH_QR(y[2], y[6], y[10], y[14], 16u, 12u, 8u, 7u) MH_QR(y[3], y[7], y[11], y[15], 16u, 12u, 8u, 7u)
MH_QR(y[0], y[5], y[10], y[15], 16u, 12u, 8u, 7u) MH_QR(y[1], y[6], y[11], y[12], 16u, 12u, 8u, 7u)
MH_QR(y[2], y[7], y[8], y[13], 16u, 12u, 8u, 7u) MH_QR(y[3], y[4], y[9], y[14], 16u, 12u, 8u, 7u)
}
for (uint32_t i = 0u; i < 16u; ++i) y[i] += x[i];
}
// One cache segment: 64 chained lines written at cache[seg * 1024]. in_j = prev ^ (sigma || K || seg || j || tag), prev_0 = 0.
IGNEUM_HD void mh_cache_segment(uint32_t* cache, uint32_t seg) {
uint32_t prev[16]; uint32_t x[16]; uint32_t y[16];
for (uint32_t i = 0u; i < 16u; ++i) prev[i] = 0u;
for (uint32_t j = 0u; j < MH_SEGMENT_LINES; ++j) {
x[0] = 0x61707865u ^ prev[0]; x[1] = 0x3320646eu ^ prev[1]; x[2] = 0x79622d32u ^ prev[2]; x[3] = 0x6b206574u ^ prev[3];
x[4] = 0x3067619fu ^ prev[4];
x[5] = 0x3c269176u ^ prev[5];
x[6] = 0x84a03b03u ^ prev[6];
x[7] = 0xf8c63294u ^ prev[7];
x[8] = 0xff977c5bu ^ prev[8];
x[9] = 0xe60def3eu ^ prev[9];
x[10] = 0x63630141u ^ prev[10];
x[11] = 0xb8fbcb58u ^ prev[11];
x[12] = seg ^ prev[12]; x[13] = j ^ prev[13]; x[14] = 0x49676e65u ^ prev[14]; x[15] = 0x756d4d48u ^ prev[15];
mh_chacha_block(x, y);
uint32_t* line = cache + ((seg * MH_SEGMENT_LINES + j) * 16u);
for (uint32_t i = 0u; i < 16u; ++i) { line[i] = y[i]; prev[i] = y[i]; }
}
}
// M_r: per word (s ^ (RC + rk)) * MUL, then a column round and a diagonal round with the seed-drawn rotations.
IGNEUM_HD void mh_mixer(uint32_t* s, uint32_t rk) {
s[0] = (s[0] ^ (0xbab68293u + rk)) * 0x42146205u;
s[1] = (s[1] ^ (0xcc162340u + rk)) * 0x52cbe0fbu;
s[2] = (s[2] ^ (0x6ce151ccu + rk)) * 0x7ecf4a03u;
s[3] = (s[3] ^ (0xe62b8997u + rk)) * 0x6728907fu;
s[4] = (s[4] ^ (0xc9c80297u + rk)) * 0xd81d9751u;
s[5] = (s[5] ^ (0xf74a1654u + rk)) * 0x132952c3u;
s[6] = (s[6] ^ (0x3d704af5u + rk)) * 0xf60de277u;
s[7] = (s[7] ^ (0x3cf522b7u + rk)) * 0x05358035u;
s[8] = (s[8] ^ (0x2b9cac04u + rk)) * 0xbaf6499du;
s[9] = (s[9] ^ (0xa880ac10u + rk)) * 0xe4db9667u;
s[10] = (s[10] ^ (0x13e5dd1du + rk)) * 0x3e98f45du;
s[11] = (s[11] ^ (0x6fc3e233u + rk)) * 0xd0004eddu;
s[12] = (s[12] ^ (0x2d83eeacu + rk)) * 0x2691630du;
s[13] = (s[13] ^ (0x9006e8bfu + rk)) * 0x9beb3bcfu;
s[14] = (s[14] ^ (0x2c4b5362u + rk)) * 0xab310379u;
s[15] = (s[15] ^ (0x31b49ee2u + rk)) * 0x99cfb423u;
MH_QR(s[0], s[4], s[8], s[12], 20u, 20u, 19u, 4u) MH_QR(s[1], s[5], s[9], s[13], 20u, 20u, 19u, 4u)
MH_QR(s[2], s[6], s[10], s[14], 20u, 20u, 19u, 4u) MH_QR(s[3], s[7], s[11], s[15], 20u, 20u, 19u, 4u)
MH_QR(s[0], s[5], s[10], s[15], 26u, 3u, 3u, 27u) MH_QR(s[1], s[6], s[11], s[12], 26u, 3u, 3u, 27u)
MH_QR(s[2], s[7], s[8], s[13], 26u, 3u, 3u, 27u) MH_QR(s[3], s[4], s[9], s[14], 26u, 3u, 3u, 27u)
}
// Item t: 16 words. s = (K, t * MUL[i] + RC[i]); 8 rounds of 8 x mixer + cache line s[0] & mask; 8 x final mixer.
IGNEUM_HD void mh_item(const uint32_t* cache, uint32_t t, uint32_t* s) {
s[0] = 0x3067619fu;
s[1] = 0x3c269176u;
s[2] = 0x84a03b03u;
s[3] = 0xf8c63294u;
s[4] = 0xff977c5bu;
s[5] = 0xe60def3eu;
s[6] = 0x63630141u;
s[7] = 0xb8fbcb58u;
s[8] = t * 0x42146205u + 0xbab68293u;
s[9] = t * 0x52cbe0fbu + 0xcc162340u;
s[10] = t * 0x7ecf4a03u + 0x6ce151ccu;
s[11] = t * 0x6728907fu + 0xe62b8997u;
s[12] = t * 0xd81d9751u + 0xc9c80297u;
s[13] = t * 0x132952c3u + 0xf74a1654u;
s[14] = t * 0xf60de277u + 0x3d704af5u;
s[15] = t * 0x05358035u + 0x3cf522b7u;
for (uint32_t r = 0u; r < 8u; ++r) {
for (uint32_t j = 0u; j < 8u; ++j) mh_mixer(s, 0x9E3779B9u * (r * 8u + j + 1u));
const uint32_t* line = cache + ((s[0] & MH_CACHE_LINE_MASK) * 16u);
for (uint32_t i = 0u; i < 16u; ++i) s[i] ^= line[i];
}
for (uint32_t j = 0u; j < 8u; ++j) mh_mixer(s, 0x9E3779B9u * (64u + j + 1u));
}
// dataset[w] without the dataset: derive item w >> 4 and take word w & 15.
IGNEUM_HD uint32_t mh_word(const uint32_t* cache, uint32_t w) { uint32_t s[16]; mh_item(cache, w >> 4u, s); return s[w & 15u]; }