skip to content
==> src/sha256d.c <==
1/* sha256d: Bitcoin-style double SHA-256 nonce grinding.
2 *
3 * A job program (plan F5): every chunk of 1 << chunk_log2 nonces is an item of
4 * a fleet job, leased by the leader and run as OP_JOB. The threads hash the
5 * chunk in parallel, ILP hashes per thread per iteration. The first 64-byte
6 * block of the header is constant, so its compression (the midstate) is
7 * computed once per header change and kept in the view.
8 *
9 * Nonce space: chunk g covers position p = g << chunk_log2: nonces base +
10 * (p mod 2^32) .. + chunk, with the header time rolled by p >> 32 (ntime =
11 * time + roll), so the search never repeats. chunk_log2 is the manifest's
12 * `param` (PX_PARAM), so every member of a cluster grinds the same chunk; a
13 * param outside CHUNK_LOG2_MIN..=CHUNK_LOG2_MAX fails every OP_JOB. When it
14 * changes (an upgrade) the next task restarts the search with the new size.
15 *
16 * Hash order: compared as a little-endian 256-bit number (Bitcoin): its most
17 * significant 32-bit word is bswap(H[7]) of the second SHA-256's state. The
18 * view stores hashes and the target as 32 bytes in that order.
19 *
20 * Hot loop: each thread keeps only its best (hash top 64 bits, nonce) and a
21 * candidate flag (top word <= the target's). If any thread saw a candidate,
22 * warp 0 rescans the chunk with the full compare and records every share, so
23 * the share count is exact and the hot loop has no data-dependent stores.
24 *
25 * Consistency: configuration is written by lane 0 of whichever node runs the
26 * op, under the view's spin lock, with gen odd meanwhile. A task reads the
27 * configuration under the gen seqlock and records its results under the lock
28 * only if gen is unchanged; a chunk that straddled a change is stale.
29 *
30 * Ops: OP_JOB grind chunk V_JOB_BASE + arg (its share count, or R_JOB_FAIL);
31 * OP_REQ (text or raw, below); 3 target = arg leading zero bits (1..=255); 4
32 * reset the stats; 5 target from compact nbits = arg; 6 the genesis header,
33 * nonce base 0, target arg zero bits (0: the header's own nbits); 7 refused
34 * (the chunk is the manifest's param); 8 nonce base = arg; 9 header time = arg.
35 * Request window: whitespace-separated `header <160 hex>`, `target <64 hex,
36 * display order>`, `zbits <n>`, `nbits <8 hex>`, `base <n>`, `time <n>`,
37 * `genesis`, `reset`, `status`; or raw bytes: 80 (header) or 112 (header,
38 * then the target in internal order), when the first byte is not a lowercase
39 * letter. The response is one text line (`ok ...` or `err ...`).
40 * Ported from alpha-rust-mesh programs/sha256d/src/lib.rs. */
41#include "mesh/prog/sha256d.h"
42#include "mesh/rt.h"
43
44/* The Bitcoin genesis block header, as 20 little-endian words. */
45static const uint32_t SHA_GENESIS[20] = {
46    0x00000001u, 0, 0, 0, 0, 0, 0, 0, 0, 0xfdeda33bu, 0xb2127b7au, 0x3e2cc77au, 0x618f7667u, 0xc31bc87fu, 0x32518a88u,
47    0xaab89f3au, 0x4a5e1e4bu, 0x495fab29u, 0x1d00ffffu, 0x7c2bac1du,
48};
49
50static const uint32_t SHA_K[64] = {
51    0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, 0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
52    0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u, 0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
53    0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu, 0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
54    0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u, 0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
55    0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u, 0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
56    0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u, 0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
57    0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u, 0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
58    0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u, 0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u,
59};
60static const uint32_t SHA_IV[8] = {0x6a09e667u, 0xbb67ae85u, 0x3c6ef372u, 0xa54ff53au, 0x510e527fu, 0x9b05688cu, 0x1f83d9abu, 0x5be0cd19u};
61
62#define SHA_INLINE static inline __attribute__((always_inline))
63
64/* A rotate (a funnel shift, shf.r.wrap.b32, on the GPU). */
65SHA_INLINE uint32_t sha_rotr(uint32_t x, uint32_t n) { return (x >> n) | (x << ((32u - n) & 31u)); }
66SHA_INLINE uint32_t sha_bsig0(uint32_t a) { return sha_rotr(a, 2) ^ sha_rotr(a, 13) ^ sha_rotr(a, 22); }
67SHA_INLINE uint32_t sha_bsig1(uint32_t e) { return sha_rotr(e, 6) ^ sha_rotr(e, 11) ^ sha_rotr(e, 25); }
68SHA_INLINE uint32_t sha_ssig0(uint32_t x) { return sha_rotr(x, 7) ^ sha_rotr(x, 18) ^ (x >> 3); }
69SHA_INLINE uint32_t sha_ssig1(uint32_t x) { return sha_rotr(x, 17) ^ sha_rotr(x, 19) ^ (x >> 10); }
70SHA_INLINE uint32_t sha_ch(uint32_t e, uint32_t f, uint32_t g) { return g ^ (e & (f ^ g)); }
71SHA_INLINE uint32_t sha_maj(uint32_t a, uint32_t b, uint32_t c) { return (a & b) | (c & (a | b)); }
72/* Byte swap (prmt on the GPU). */
73SHA_INLINE uint32_t sha_bswap(uint32_t x) { return __builtin_bswap32(x); }
74
75/* Round i of N independent messages: r = i mod 16 (the schedule window's
76 * slot), kc = K[i]. N is ILP (2) or 1; every call is inlined with constants,
77 * so the window's slots are registers. */
78SHA_INLINE void sha_round(uint32_t s[8][SHA_ILP], uint32_t w[16][SHA_ILP], uint32_t n, uint32_t r, uint32_t kc, bool expand) {
79    for (uint32_t j = 0; j < n; j++) {
80        if (expand) {
81            uint32_t x = w[(r + 14) & 15][j], y = w[(r + 1) & 15][j];
82            w[r][j] = w[r][j] + sha_ssig1(x) + w[(r + 9) & 15][j] + sha_ssig0(y);
83        }
84        uint32_t a = s[0][j], b = s[1][j], c = s[2][j], d = s[3][j], e = s[4][j], f = s[5][j], g = s[6][j], h = s[7][j];
85        uint32_t t1 = h + sha_bsig1(e) + sha_ch(e, f, g) + kc + w[r][j];
86        uint32_t t2 = sha_bsig0(a) + sha_maj(a, b, c);
87        s[7][j] = g;
88        s[6][j] = f;
89        s[5][j] = e;
90        s[4][j] = d + t1;
91        s[3][j] = c;
92        s[2][j] = b;
93        s[1][j] = a;
94        s[0][j] = t1 + t2;
95    }
96}
97
98/* The 64 rounds. Rounds 0..16 (message words, often constant) and 48..64
99 * (whose tail the hot loop does not use) are unrolled so constants fold and
100 * dead rounds drop; rounds 16..48 are a 2-trip loop over 16 unrolled rounds,
101 * which keeps the hot loop's code small enough for the instruction cache. */
102SHA_INLINE void sha_rounds64(uint32_t s[8][SHA_ILP], uint32_t w[16][SHA_ILP], uint32_t n) {
103    for (uint32_t r = 0; r < 16; r++) sha_round(s, w, n, r, SHA_K[r], false);
104#if defined(__clang__)
105#pragma clang loop unroll(disable)
106#endif
107    for (uint32_t b = 16; b < 48; b += 16) {
108#if defined(__clang__)
109#pragma clang loop unroll(full)
110#endif
111        for (uint32_t r = 0; r < 16; r++) sha_round(s, w, n, r, SHA_K[b + r], true);
112    }
113    for (uint32_t r = 0; r < 16; r++) sha_round(s, w, n, r, SHA_K[48 + r], true);
114}
115
116/* SHA256d of n headers that differ only in the nonce: mid is the first
117 * block's state, w0..w2 the second block's first words (big-endian), nonce_be
118 * the byte-swapped nonces. Leaves the second SHA-256's state words H[0..8]
119 * (the hash bytes are their big-endian serialization) in out. */
120SHA_INLINE void sha_sha256d(const uint32_t mid[8], uint32_t w0, uint32_t w1, uint32_t w2, const uint32_t nonce_be[SHA_ILP],
121                            uint32_t n, uint32_t out[8][SHA_ILP]) {
122    uint32_t s[8][SHA_ILP], w[16][SHA_ILP];
123    for (uint32_t j = 0; j < n; j++) {
124        for (uint32_t k = 0; k < 8; k++) s[k][j] = mid[k];
125        for (uint32_t k = 0; k < 16; k++) w[k][j] = 0;
126        w[0][j] = w0, w[1][j] = w1, w[2][j] = w2, w[3][j] = nonce_be[j], w[4][j] = 0x80000000u, w[15][j] = 640;
127    }
128    sha_rounds64(s, w, n);
129    for (uint32_t j = 0; j < n; j++) {
130        for (uint32_t k = 0; k < 16; k++) w[k][j] = 0;
131        for (uint32_t k = 0; k < 8; k++) w[k][j] = s[k][j] + mid[k];
132        w[8][j] = 0x80000000u, w[15][j] = 256;
133        for (uint32_t k = 0; k < 8; k++) s[k][j] = SHA_IV[k];
134    }
135    sha_rounds64(s, w, n);
136    for (uint32_t j = 0; j < n; j++)
137        for (uint32_t k = 0; k < 8; k++) out[k][j] = s[k][j] + SHA_IV[k];
138}
139
140/* One SHA256d as a little-endian 256-bit number (words, 7 most significant).
141 * Cold paths only (the best hash, the share rescan): one shared copy. */
142__attribute__((noinline)) static void sha_hash1(const uint32_t mid[8], uint32_t w0, uint32_t w1, uint32_t w2, uint32_t nonce, uint32_t out[8]) {
143    uint32_t nb[SHA_ILP] = {sha_bswap(nonce), 0}, h[8][SHA_ILP];
144    sha_sha256d(mid, w0, w1, w2, nb, 1, h);
145    for (uint32_t k = 0; k < 8; k++) out[k] = sha_bswap(h[k][0]);
146}
147
148/* ---- the view's spin lock and configuration (lane 0) */
149static void sha_lock(mesh_view v) {
150    uint8_t *p = mesh_view_ptr(v) + SHA_V_LOCK;
151    while (mesh_rt_atom_cas(p, 0, 1) != 0) mesh_rt_nanosleep(64);
152    mesh_rt_fence_acq_rel();
153}
154static void sha_unlock(mesh_view v) {
155    mesh_rt_fence_acq_rel();
156    mesh_rt_st_release(mesh_view_ptr(v) + SHA_V_LOCK, 0);
157}
158/* A configuration change begins (locked, gen odd); returns the odd gen for sha_config_end. */
159static uint32_t sha_config_begin(mesh_view v) {
160    sha_lock(v);
161    uint8_t *gp = mesh_view_ptr(v) + SHA_V_GEN;
162    uint32_t g = mesh_rt_ld_relaxed(gp) | 1u;
163    mesh_rt_st_relaxed(gp, g);
164    mesh_rt_fence_acq_rel();
165    return g;
166}
167static void sha_config_end(mesh_view v, uint32_t g) {
168    mesh_rt_fence_acq_rel();
169    mesh_rt_st_release(mesh_view_ptr(v) + SHA_V_GEN, g + 1);
170    sha_unlock(v);
171}
172
173/* ---- 256-bit helpers (words k = 7 most significant) */
174static uint32_t sha_le_word(uint32_t h) { return sha_bswap(h); }
175/* Leading zero bits of a little-endian 256-bit number given as words. */
176static uint32_t sha_zbits_of(const uint32_t w[8]) {
177    uint32_t z = 0;
178    bool done = false;
179    for (int k = 7; k >= 0; k--)
180        if (!done) {
181            if (w[k] == 0) z += 32;
182            else { z += (uint32_t)__builtin_clz(w[k]); done = true; }
183        }
184    return z;
185}
186static void sha_read8(mesh_view v, uint32_t off, uint32_t w[8]) { for (uint32_t k = 0; k < 8; k++) w[k] = mesh_view_u32(v, off + 4 * k); }
187static void sha_write8(mesh_view v, uint32_t off, const uint32_t w[8]) { for (uint32_t k = 0; k < 8; k++) mesh_view_set_u32(v, off + 4 * k, w[k]); }
188/* Compares little-endian 256-bit numbers: -1, 0, 1 (the most significant differing word decides). */
189static int sha_cmp256(const uint32_t a[8], const uint32_t b[8]) {
190    int r = 0;
191    for (int k = 0; k < 8; k++)
192        if (a[k] != b[k]) r = a[k] < b[k] ? -1 : 1;
193    return r;
194}
195
196/* The midstate of the header's first 64 bytes (cold: one shared copy). */
197__attribute__((noinline)) static void sha_set_midstate(mesh_view v) {
198    uint32_t s[8][SHA_ILP], w[16][SHA_ILP];
199    for (uint32_t k = 0; k < 8; k++) s[k][0] = SHA_IV[k];
200    /* Unchecked reads: init checked view_len >= VIEW_MIN (fixed per image). */
201    uint8_t *hp = mesh_view_ptr(v) + SHA_V_HEADER;
202    for (uint32_t k = 0; k < 16; k++) w[k][0] = sha_bswap(mesh_rt_rd(hp + 4 * k));
203    sha_rounds64(s, w, 1);
204    for (uint32_t k = 0; k < 8; k++) mesh_view_set_u32(v, SHA_V_MID + 4 * k, s[k][0] + SHA_IV[k]);
205}
206
207static void sha_clear_shares(mesh_view v) {
208    mesh_view_set_u32(v, SHA_V_SHARES, 0);
209    mesh_view_set_u32(v, SHA_V_FOUND, 0);
210    mesh_view_set_u32(v, SHA_V_LAST_NONCE, 0);
211    mesh_view_set_u32(v, SHA_V_LAST_TIME, 0);
212    mesh_view_set_u32(v, SHA_V_LAST_ZBITS, 0);
213    for (uint32_t o = SHA_V_RING; o < SHA_V_RING + SHA_RING * SHA_RING_BYTES; o += 4) mesh_view_set_u32(v, o, 0);
214}
215static void sha_clear_best(mesh_view v) {
216    const uint32_t all[8] = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
217    sha_write8(v, SHA_V_BEST, all);
218    mesh_view_set_u32(v, SHA_V_BEST_ZBITS, 0);
219    mesh_view_set_u32(v, SHA_V_BEST_NONCE, 0);
220    mesh_view_set_u32(v, SHA_V_BEST_TIME, 0);
221    mesh_view_set_u32(v, SHA_V_BEST_HI, UINT32_MAX);
222}
223/* A new search over the same header (base, chunk, time or header changed). */
224static void sha_restart(mesh_view v) {
225    sha_clear_best(v);
226    sha_clear_shares(v);
227}
228/* The header at V_HEADER changed: its copies, the midstate, a new search. */
229static void sha_header_changed(mesh_view v) {
230    mesh_view_set_u32(v, SHA_V_VERSION, mesh_view_u32(v, SHA_V_HEADER));
231    mesh_view_set_u32(v, SHA_V_TIME, mesh_view_u32(v, SHA_V_HEADER + 68));
232    mesh_view_set_u32(v, SHA_V_NBITS, mesh_view_u32(v, SHA_V_HEADER + 72));
233    mesh_view_set_u32(v, SHA_V_HEADERS, mesh_view_u32(v, SHA_V_HEADERS) + 1);
234    sha_set_midstate(v);
235    sha_restart(v);
236}
237static void sha_target_changed(mesh_view v) {
238    uint32_t t[8];
239    sha_read8(v, SHA_V_TARGET, t);
240    mesh_view_set_u32(v, SHA_V_TARGET_ZBITS, sha_zbits_of(t));
241    sha_clear_shares(v);
242}
243/* Target = 2^(256 - z) - 1 (z leading zero bits). */
244static void sha_set_zbits(mesh_view v, uint32_t z) {
245    uint32_t lim = 256 - z;
246    for (uint32_t k = 0; k < 8; k++) {
247        uint32_t lo = 32 * k;
248        uint32_t w = lo + 32 <= lim ? UINT32_MAX : lo >= lim ? 0 : (1u << (lim - lo)) - 1;
249        mesh_view_set_u32(v, SHA_V_TARGET + 4 * k, w);
250    }
251    sha_target_changed(v);
252}
253/* Target from compact bits (mantissa * 256^(exp - 3)); false if negative or overflowing. */
254static bool sha_set_nbits(mesh_view v, uint32_t bits) {
255    uint32_t exp = bits >> 24, mant = bits & 0x007fffffu;
256    if ((bits & 0x00800000u) || exp > 32) return false;
257    int32_t pos = (int32_t)exp - 3;
258    if (pos < 0) { mant >>= 8 * (uint32_t)(-pos); pos = 0; }
259    for (uint32_t k = 0; k < 8; k++) mesh_view_set_u32(v, SHA_V_TARGET + 4 * k, 0);
260    for (uint32_t i = 0; i < 3; i++) {
261        uint32_t b = (mant >> (8 * i)) & 0xff, at = (uint32_t)pos + i;
262        if (at < 32) mesh_view_set_u8(v, SHA_V_TARGET + at, (uint8_t)b);
263        else if (b != 0) return false;
264    }
265    sha_target_changed(v);
266    return true;
267}
268static void sha_set_genesis(mesh_view v) {
269    for (uint32_t k = 0; k < 20; k++) mesh_view_set_u32(v, SHA_V_HEADER + 4 * k, SHA_GENESIS[k]);
270    mesh_view_set_u32(v, SHA_V_BASE, 0);
271    sha_header_changed(v);
272}
273static void sha_reset_stats(mesh_view v) {
274    mesh_view_set_u64(v, SHA_V_HASHES, 0);
275    sha_clear_best(v);
276    sha_clear_shares(v);
277}
278
279static void sha_init(const mesh_ctx *ctx) {
280    if (!mesh_ctx_leader(ctx)) return;
281    mesh_view v = mesh_ctx_view(ctx);
282    /* A view smaller than the layout faults here (bounds-checked), loudly. */
283    if (mesh_view_len(v) < SHA_VIEW_MIN) { (void)mesh_view_u32(v, SHA_VIEW_MIN - 4); return; }
284    uint32_t g = sha_config_begin(v);
285    mesh_view_set_u32(v, SHA_V_MAGIC, SHA_MAGIC);
286    mesh_view_set_u32(v, SHA_V_CHUNK_LOG2, mesh_ctx_param(ctx));
287    mesh_view_set_u32(v, SHA_V_SYSTEM, mesh_ctx_system(ctx));
288    sha_set_genesis(v);
289    sha_set_zbits(v, SHA_ZBITS_DEFAULT);
290    sha_reset_stats(v);
291    sha_config_end(v, g);
292}
293
294/* The chunk size the manifest gives (false: out of range). */
295static bool sha_chunk_log2(const mesh_ctx *ctx, uint32_t *c) {
296    *c = mesh_ctx_param(ctx);
297    return *c >= SHA_CHUNK_LOG2_MIN && *c <= SHA_CHUNK_LOG2_MAX;
298}
299/* Lane 0: if the param changed since the search began (an upgrade), restart
300 * the search with the new size (once: rechecked under the lock). */
301static void sha_sync_chunk(mesh_view v, uint32_t clog) {
302    if (mesh_view_u32(v, SHA_V_CHUNK_LOG2) != clog) {
303        uint32_t g = sha_config_begin(v);
304        if (mesh_view_u32(v, SHA_V_CHUNK_LOG2) != clog) {
305            mesh_view_set_u32(v, SHA_V_CHUNK_LOG2, clog);
306            sha_restart(v);
307        }
308        sha_config_end(v, g);
309    }
310}
311
312/* One share into the ring (lane 0), if the configuration is still g. */
313__attribute__((noinline)) static void sha_record_share(const mesh_ctx *ctx, mesh_view v, uint32_t g, uint32_t nonce, uint32_t ntime, const uint32_t h[8]) {
314    sha_lock(v);
315    if (mesh_rt_ld_relaxed(mesh_view_ptr(v) + SHA_V_GEN) == g) {
316        uint32_t s = mesh_view_u32(v, SHA_V_SHARES);
317        uint32_t e = SHA_V_RING + (s % SHA_RING) * SHA_RING_BYTES;
318        uint32_t z = sha_zbits_of(h);
319        mesh_view_set_u32(v, e, nonce);
320        mesh_view_set_u32(v, e + 4, ntime);
321        mesh_view_set_u32(v, e + 8, s + 1);
322        mesh_view_set_u32(v, e + 12, z);
323        sha_write8(v, e + 16, h);
324        mesh_view_set_u32(v, SHA_V_SHARES, s + 1);
325        mesh_view_set_u32(v, SHA_V_LAST_NONCE, nonce);
326        mesh_view_set_u32(v, SHA_V_LAST_TIME, ntime);
327        mesh_view_set_u32(v, SHA_V_LAST_ZBITS, z);
328        mesh_view_set_u32(v, SHA_V_FOUND, 1);
329        mesh_ctx_count(ctx, 1, 1);
330    }
331    sha_unlock(v);
332}
333
334/* The node's shared memory: the configuration warp 0 read (CFG_WORDS words). */
335#define SHA_CFG_WORDS 21u
336
337/* One leased chunk (OP_JOB: chunk V_JOB_BASE + job): hash, record. Every thread
338 * of the node: warp 0 reads the configuration into shared memory, the node
339 * grinds the chunk (nonce thread + threads x i), the best hash and the
340 * candidate flag by block reductions, then warp 0 alone records (and rescans
341 * the chunk when a thread saw a candidate: rare). */
342static uint32_t sha_grind(const mesh_ctx *ctx, uint32_t job) {
343    mesh_view v = mesh_ctx_view(ctx);
344    uint32_t lane = mesh_ctx_lane(ctx);
345    uint8_t *gp = mesh_view_ptr(v) + SHA_V_GEN;
346    uint32_t clog;
347    if (!sha_chunk_log2(ctx, &clog)) return MESH_R_JOB_FAIL;
348    mesh_shared cfg;
349    if (!mesh_ctx_shared(ctx, 0, SHA_CFG_WORDS, 4, &cfg)) return MESH_R_JOB_FAIL;
350    /* Threads at work: all, or (a chunk smaller than threads x ILP) the first chunk / ILP. */
351    uint32_t threads = mesh_ctx_threads(ctx) < (1u << clog) / SHA_ILP ? mesh_ctx_threads(ctx) : (1u << clog) / SHA_ILP;
352    if (mesh_ctx_warp(ctx) == 0) {
353        if (lane == 0) sha_sync_chunk(v, clog);
354        mesh_rt_warp_sync();
355        /* Configuration under the gen seqlock. */
356        uint32_t g, mid[8], hw[3], base, tgt[8];
357        for (;;) {
358            uint32_t g1 = 0;
359            if (lane == 0) {
360                g1 = mesh_rt_ld_acquire(gp);
361                while (g1 & 1u) { mesh_rt_nanosleep(256); g1 = mesh_rt_ld_acquire(gp); }
362            }
363            g1 = mesh_rt_shfl_idx(g1, 0);
364            mesh_rt_warp_sync();
365            sha_read8(v, SHA_V_MID, mid);
366            hw[0] = mesh_view_u32(v, SHA_V_HEADER + 64), hw[1] = mesh_view_u32(v, SHA_V_HEADER + 68), hw[2] = mesh_view_u32(v, SHA_V_HEADER + 72);
367            base = mesh_view_u32(v, SHA_V_BASE);
368            sha_read8(v, SHA_V_TARGET, tgt);
369            mesh_rt_fence_acq_rel();
370            mesh_rt_warp_sync();
371            uint32_t g2 = lane == 0 ? mesh_rt_ld_acquire(gp) : 0;
372            if (mesh_rt_shfl_idx(g2, 0) == g1) { g = g1; break; }
373            /* Read across a change: again under the new gen. */
374        }
375        if (lane == 0) {
376            const uint32_t head[5] = {g, base, hw[0], hw[1], hw[2]};
377            for (uint32_t i = 0; i < 5; i++) mesh_shared_set_u32(cfg, i, head[i]);
378            for (uint32_t i = 0; i < 8; i++) mesh_shared_set_u32(cfg, 5 + i, mid[i]);
379            for (uint32_t i = 0; i < 8; i++) mesh_shared_set_u32(cfg, 13 + i, tgt[i]);
380        }
381    }
382    mesh_ctx_block_barrier(ctx);
383    uint32_t g = mesh_shared_get_u32(cfg, 0), base = mesh_shared_get_u32(cfg, 1);
384    uint32_t hw[3] = {mesh_shared_get_u32(cfg, 2), mesh_shared_get_u32(cfg, 3), mesh_shared_get_u32(cfg, 4)};
385    uint32_t mid[8], tgt[8];
386    for (uint32_t i = 0; i < 8; i++) mid[i] = mesh_shared_get_u32(cfg, 5 + i), tgt[i] = mesh_shared_get_u32(cfg, 13 + i);
387    uint64_t gidx = mesh_view_u64(v, SHA_V_JOB_BASE) + job;
388    /* This item's result record: lane 0 fills it. */
389    uint32_t rec = SHA_V_JOB_OUT + SHA_JOB_REC * (mesh_ctx_ticket(ctx) % MESH_PROG_RESULTS);
390    uint32_t found = 0;
391    uint64_t p = gidx << clog;
392    uint32_t nonce0 = base + (uint32_t)p;
393    uint32_t ntime = hw[1] + (uint32_t)(p >> 32);
394    uint32_t w0 = sha_bswap(hw[0]), w1 = sha_bswap(ntime), w2 = sha_bswap(hw[2]);
395    uint32_t t7 = tgt[7];
396
397    /* The hot loop: registers only. Thread t takes nonces t + threads x i. */
398    uint32_t th = mesh_ctx_thread(ctx);
399    uint32_t iters = th < threads ? (1u << clog) / (threads * SHA_ILP) : 0;
400    uint32_t bh = UINT32_MAX, bl = UINT32_MAX, bn = 0;
401    bool cand = false;
402    for (uint32_t k = 0; k < iters; k++) {
403        uint32_t n[SHA_ILP], nb[SHA_ILP], h[8][SHA_ILP];
404        for (uint32_t j = 0; j < SHA_ILP; j++) {
405            n[j] = nonce0 + th + threads * (k * SHA_ILP + j);
406            nb[j] = sha_bswap(n[j]);
407        }
408        sha_sha256d(mid, w0, w1, w2, nb, SHA_ILP, h);
409        for (uint32_t j = 0; j < SHA_ILP; j++) {
410            uint32_t hi = sha_le_word(h[7][j]), lo = sha_le_word(h[6][j]);
411            if (hi < bh || (hi == bh && lo < bl)) { bh = hi; bl = lo; bn = n[j]; }
412            cand |= hi <= t7;
413        }
414    }
415
416    /* The node's best (hi, lo, then the least nonce), the same on every thread; any candidate. */
417    uint64_t mine = (uint64_t)bh << 32 | bl;
418    uint64_t key = mesh_ctx_block_reduce_u64(ctx, mine, UINT64_MAX, mesh_rt_min_u64);
419    bn = mesh_ctx_block_reduce_u32(ctx, mine == key ? bn : UINT32_MAX, UINT32_MAX, mesh_rt_min_u32);
420    bool any = mesh_ctx_block_max_u32(ctx, cand ? 1u : 0u) != 0;
421    /* Warp 0 alone from here (no block collective follows). */
422    if (mesh_ctx_warp(ctx) != 0) return 0;
423    uint32_t best[8];
424    sha_hash1(mid, w0, w1, w2, bn, best);
425
426    bool stale = false;
427    if (lane == 0) {
428        sha_lock(v);
429        if (mesh_rt_ld_relaxed(gp) == g) {
430            uint64_t n = (uint64_t)1 << clog;
431            uint64_t old = mesh_view_u64(v, SHA_V_HASHES);
432            mesh_view_set_u64(v, SHA_V_HASHES, old + n);
433            mesh_ctx_count(ctx, 0, (uint32_t)((old + n) / 1000000 - old / 1000000));
434            mesh_ctx_count(ctx, 2, 1);
435            mesh_view_set_u32(v, SHA_V_SYSTEM, mesh_ctx_system(ctx));
436            uint32_t cur[8];
437            sha_read8(v, SHA_V_BEST, cur);
438            if (sha_cmp256(best, cur) < 0) {
439                sha_write8(v, SHA_V_BEST, best);
440                mesh_view_set_u32(v, SHA_V_BEST_ZBITS, sha_zbits_of(best));
441                mesh_view_set_u32(v, SHA_V_BEST_NONCE, bn);
442                mesh_view_set_u32(v, SHA_V_BEST_TIME, ntime);
443                mesh_view_set_u32(v, SHA_V_BEST_HI, best[7]);
444            }
445        } else {
446            stale = true;
447            mesh_ctx_count(ctx, 3, 1);
448        }
449        sha_unlock(v);
450    }
451    if (mesh_rt_shfl_idx(stale ? 1u : 0u, 0) != 0) return MESH_R_JOB_FAIL;
452
453    /* Shares: a full rescan of the chunk by warp 0 if any thread saw a
454     * candidate, one nonce per lane per step. */
455    if (any) {
456        for (uint32_t k = 0; k < (1u << clog) / 32; k++) {
457            uint32_t nonce = nonce0 + lane + 32 * k;
458            uint32_t hh[8];
459            sha_hash1(mid, w0, w1, w2, nonce, hh);
460            uint32_t bits = mesh_rt_ballot(sha_cmp256(hh, tgt) <= 0);
461            while (bits != 0) {
462                uint32_t src = (uint32_t)__builtin_ctz(bits);
463                bits &= bits - 1;
464                uint32_t n = mesh_rt_shfl_idx(nonce, src);
465                uint32_t sh[8];
466                for (uint32_t q = 0; q < 8; q++) sh[q] = mesh_rt_shfl_idx(hh[q], src);
467                if (lane == 0) {
468                    sha_record_share(ctx, v, g, n, ntime, sh);
469                    if (found < SHA_JOB_SHARES) {
470                        mesh_view_set_u32(v, rec + 4 + 8 * found, n);
471                        mesh_view_set_u32(v, rec + 8 + 8 * found, sha_zbits_of(sh));
472                    }
473                    found++;
474                }
475            }
476        }
477    }
478    /* The record, then the result (meshd reads the record once the completion is published). */
479    found = mesh_rt_shfl_idx(found, 0);
480    if (lane == 0) {
481        mesh_view_set_u32(v, rec, found);
482        for (uint32_t i = found; i < SHA_JOB_SHARES; i++) {
483            mesh_view_set_u32(v, rec + 4 + 8 * i, 0);
484            mesh_view_set_u32(v, rec + 8 + 8 * i, 0);
485        }
486        mesh_view_set_u32(v, rec + 4 + 8 * SHA_JOB_SHARES, ntime);
487    }
488    return found;
489}
490
491/* ---- request window (lane 0) */
492typedef struct {
493    mesh_view v;
494    uint32_t n;
495} sha_out;
496static void out_b(sha_out *o, uint8_t c) {
497    if (o->n < mesh_view_len(o->v)) { mesh_view_set_u8(o->v, o->n, c); o->n++; }
498}
499static void out_s(sha_out *o, const char *s) { for (; *s; s++) out_b(o, (uint8_t)*s); }
500static void out_dec(sha_out *o, uint64_t x) {
501    uint64_t d = 1;
502    while (x / d >= 10) d *= 10;
503    for (;;) {
504        out_b(o, (uint8_t)('0' + x / d));
505        x %= d;
506        if (d == 1) break;
507        d /= 10;
508    }
509}
510static void out_hex8(sha_out *o, uint8_t x) {
511    static const char hex[] = "0123456789abcdef";
512    out_b(o, (uint8_t)hex[(x >> 4) & 15]);
513    out_b(o, (uint8_t)hex[x & 15]);
514}
515static void out_kv(sha_out *o, const char *k, uint64_t x) {
516    out_b(o, ' ');
517    out_s(o, k);
518    out_b(o, '=');
519    out_dec(o, x);
520}
521
522static int sha_nib(uint8_t c) {
523    if (c >= '0' && c <= '9') return c - '0';
524    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
525    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
526    return -1;
527}
528static bool sha_is_ws(uint8_t c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0; }
529
530/* The next token of the request: start and length (0 at the end). */
531static void sha_token(mesh_view r, uint32_t *at, uint32_t *s, uint32_t *len) {
532    while (*at < mesh_view_len(r) && sha_is_ws(mesh_view_u8(r, *at))) (*at)++;
533    *s = *at;
534    while (*at < mesh_view_len(r) && !sha_is_ws(mesh_view_u8(r, *at))) (*at)++;
535    *len = *at - *s;
536}
537static bool sha_tok_is(mesh_view r, uint32_t s, uint32_t len, const char *w) {
538    uint32_t n = 0;
539    while (w[n]) n++;
540    if (len != n) return false;
541    for (uint32_t i = 0; i < len; i++)
542        if (mesh_view_u8(r, s + i) != (uint8_t)w[i]) return false;
543    return true;
544}
545static bool sha_tok_dec(mesh_view r, uint32_t s, uint32_t len, uint32_t *out) {
546    if (len == 0 || len > 10) return false;
547    uint64_t x = 0;
548    for (uint32_t i = 0; i < len; i++) {
549        uint8_t c = mesh_view_u8(r, s + i);
550        if (c < '0' || c > '9') return false;
551        x = x * 10 + (uint64_t)(c - '0');
552    }
553    if (x > UINT32_MAX) return false;
554    *out = (uint32_t)x;
555    return true;
556}
557static bool sha_tok_hex32(mesh_view r, uint32_t s, uint32_t len, uint32_t *out) {
558    if (len == 0 || len > 8) return false;
559    uint32_t x = 0;
560    for (uint32_t i = 0; i < len; i++) {
561        int d = sha_nib(mesh_view_u8(r, s + i));
562        if (d < 0) return false;
563        x = x << 4 | (uint32_t)d;
564    }
565    *out = x;
566    return true;
567}
568/* Hex bytes of the token into the view at dst (n bytes; rev: reversed, display order). */
569static bool sha_tok_bytes(mesh_view r, uint32_t s, uint32_t len, mesh_view v, uint32_t dst, uint32_t n, bool rev) {
570    if (len != 2 * n) return false;
571    for (uint32_t i = 0; i < n; i++) {
572        int a = sha_nib(mesh_view_u8(r, s + 2 * i)), b = sha_nib(mesh_view_u8(r, s + 2 * i + 1));
573        if (a < 0 || b < 0) return false;
574        mesh_view_set_u8(v, dst + (rev ? n - 1 - i : i), (uint8_t)(a << 4 | b));
575    }
576    return true;
577}
578
579#define SHA_T_NONE 0u
580#define SHA_T_ZBITS 1u
581#define SHA_T_NBITS 2u
582#define SHA_T_BYTES 3u
583
584/* Parses the whole request (into V_STAGE), then applies it as one change. */
585__attribute__((noinline)) static uint32_t sha_request(const mesh_ctx *ctx) {
586    mesh_view r = mesh_ctx_request(ctx), v = mesh_ctx_view(ctx);
587    sha_out o = {mesh_ctx_response(ctx), 0};
588    bool hdr = false, has_base = false, has_time = false, genesis = false, reset = false, status = false;
589    uint32_t tk = SHA_T_NONE, tv = 0, base = 0, time = 0;
590    const char *err = NULL;
591    uint8_t first = mesh_view_u8(r, 0);
592    if ((mesh_view_len(r) == 80 || mesh_view_len(r) == 112) && !(first >= 'a' && first <= 'z')) {
593        for (uint32_t i = 0; i < mesh_view_len(r); i++) mesh_view_set_u8(v, SHA_V_STAGE + i, mesh_view_u8(r, i));
594        hdr = true;
595        if (mesh_view_len(r) == 112) tk = SHA_T_BYTES;
596    } else {
597        uint32_t at = 0;
598        for (;;) {
599            uint32_t s, n, as, an;
600            sha_token(r, &at, &s, &n);
601            if (n == 0) break;
602            if (sha_tok_is(r, s, n, "header")) {
603                sha_token(r, &at, &as, &an);
604                if (!sha_tok_bytes(r, as, an, v, SHA_V_STAGE, 80, false)) { err = "header: 160 hex digits"; break; }
605                hdr = true;
606            } else if (sha_tok_is(r, s, n, "target")) {
607                sha_token(r, &at, &as, &an);
608                if (!sha_tok_bytes(r, as, an, v, SHA_V_STAGE + 80, 32, true)) { err = "target: 64 hex digits"; break; }
609                tk = SHA_T_BYTES;
610            } else if (sha_tok_is(r, s, n, "zbits")) {
611                uint32_t z;
612                sha_token(r, &at, &as, &an);
613                if (sha_tok_dec(r, as, an, &z) && z >= 1 && z <= 255) { tk = SHA_T_ZBITS; tv = z; }
614                else { err = "zbits: 1..=255"; break; }
615            } else if (sha_tok_is(r, s, n, "nbits")) {
616                uint32_t b;
617                sha_token(r, &at, &as, &an);
618                if (sha_tok_hex32(r, as, an, &b)) { tk = SHA_T_NBITS; tv = b; }
619                else { err = "nbits: 8 hex digits"; break; }
620            } else if (sha_tok_is(r, s, n, "base")) {
621                sha_token(r, &at, &as, &an);
622                if (sha_tok_dec(r, as, an, &base)) has_base = true;
623                else { err = "base: a u32"; break; }
624            } else if (sha_tok_is(r, s, n, "time")) {
625                sha_token(r, &at, &as, &an);
626                if (sha_tok_dec(r, as, an, &time)) has_time = true;
627                else { err = "time: a u32"; break; }
628            } else if (sha_tok_is(r, s, n, "chunk")) {
629                err = "chunk: fixed by the manifest's param (one chunk size on every member of a cluster)";
630                break;
631            } else if (sha_tok_is(r, s, n, "genesis")) {
632                genesis = true;
633            } else if (sha_tok_is(r, s, n, "reset")) {
634                reset = true;
635            } else if (sha_tok_is(r, s, n, "status")) {
636                status = true;
637            } else {
638                err = "unknown word (header target zbits nbits base time genesis reset status)";
639                break;
640            }
641        }
642    }
643    if (err) {
644        out_s(&o, "err ");
645        out_s(&o, err);
646        out_b(&o, '\n');
647        return o.n;
648    }
649    uint32_t clog;
650    if (!sha_chunk_log2(ctx, &clog)) {
651        out_s(&o, "err the manifest's param (chunk_log2) is outside 6..=24\n");
652        return o.n;
653    }
654    sha_sync_chunk(v, clog);
655    /* A pure `status` changes nothing (and keeps gen: no in-flight chunk goes stale). */
656    bool change = genesis || hdr || has_time || has_base || tk != SHA_T_NONE || reset;
657    bool ok = true;
658    if (change) {
659        uint32_t g = sha_config_begin(v);
660        if (genesis) sha_set_genesis(v);
661        if (hdr)
662            for (uint32_t i = 0; i < 80; i++) mesh_view_set_u8(v, SHA_V_HEADER + i, mesh_view_u8(v, SHA_V_STAGE + i));
663        if (has_time) mesh_view_set_u32(v, SHA_V_HEADER + 68, time);
664        if (has_base) mesh_view_set_u32(v, SHA_V_BASE, base);
665        if (hdr || has_time) sha_header_changed(v);
666        else if (has_base) sha_restart(v);
667        if (tk == SHA_T_ZBITS) sha_set_zbits(v, tv);
668        else if (tk == SHA_T_NBITS) ok = sha_set_nbits(v, tv);
669        else if (tk == SHA_T_BYTES) {
670            for (uint32_t i = 0; i < 32; i++) mesh_view_set_u8(v, SHA_V_TARGET + i, mesh_view_u8(v, SHA_V_STAGE + 80 + i));
671            sha_target_changed(v);
672        }
673        if (reset) sha_reset_stats(v);
674        sha_config_end(v, g);
675    }
676    if (!ok) {
677        out_s(&o, "err nbits: negative or overflowing target\n");
678        return o.n;
679    }
680    out_s(&o, "ok");
681    out_kv(&o, "gen", mesh_rt_ld_relaxed(mesh_view_ptr(v) + SHA_V_GEN));
682    out_kv(&o, "zbits", mesh_view_u32(v, SHA_V_TARGET_ZBITS));
683    out_kv(&o, "base", mesh_view_u32(v, SHA_V_BASE));
684    out_kv(&o, "chunk_log2", mesh_view_u32(v, SHA_V_CHUNK_LOG2));
685    out_kv(&o, "time", mesh_view_u32(v, SHA_V_TIME));
686    if (status) {
687        out_kv(&o, "hashes", mesh_view_u64(v, SHA_V_HASHES));
688        out_kv(&o, "shares", mesh_view_u32(v, SHA_V_SHARES));
689        out_kv(&o, "best_zbits", mesh_view_u32(v, SHA_V_BEST_ZBITS));
690        out_kv(&o, "best_nonce", mesh_view_u32(v, SHA_V_BEST_NONCE));
691        out_s(&o, " best=");
692        for (int i = 31; i >= 0; i--) out_hex8(&o, mesh_view_u8(v, SHA_V_BEST + (uint32_t)i));
693    }
694    out_b(&o, '\n');
695    return o.n;
696}
697
698static uint32_t sha_task(const mesh_ctx *ctx, uint32_t op, uint32_t arg) {
699    if (op == MESH_OP_JOB) return sha_grind(ctx, arg);
700    /* Everything but the grind runs on warp 0. */
701    if (mesh_ctx_warp(ctx) != 0) return MESH_R_NONE;
702    if (op == MESH_OP_REQ) {
703        uint32_t n = mesh_ctx_leader(ctx) ? sha_request(ctx) : 0;
704        n = mesh_rt_shfl_idx(n, 0);
705        mesh_ctx_respond(ctx, n);
706        return n;
707    }
708    if (op >= SHA_OP_ZBITS && op <= SHA_OP_TIME) {
709        if (!mesh_ctx_leader(ctx)) return MESH_R_NONE;
710        mesh_view v = mesh_ctx_view(ctx);
711        uint32_t c;
712        if (sha_chunk_log2(ctx, &c)) sha_sync_chunk(v, c);
713        bool ok = false;
714        uint32_t g;
715        switch (op) {
716        case SHA_OP_ZBITS:
717            if (arg >= 1 && arg <= 255) { g = sha_config_begin(v); sha_set_zbits(v, arg); sha_config_end(v, g); ok = true; }
718            break;
719        case SHA_OP_RESET: g = sha_config_begin(v); sha_reset_stats(v); sha_config_end(v, g); ok = true; break;
720        case SHA_OP_NBITS: g = sha_config_begin(v); ok = sha_set_nbits(v, arg); sha_config_end(v, g); break;
721        case SHA_OP_GENESIS:
722            if (arg <= 255) {
723                g = sha_config_begin(v);
724                sha_set_genesis(v);
725                if (arg == 0) ok = sha_set_nbits(v, mesh_view_u32(v, SHA_V_NBITS));
726                else { sha_set_zbits(v, arg); ok = true; }
727                sha_config_end(v, g);
728            }
729            break;
730        case SHA_OP_BASE: g = sha_config_begin(v); mesh_view_set_u32(v, SHA_V_BASE, arg); sha_restart(v); sha_config_end(v, g); ok = true; break;
731        case SHA_OP_TIME: g = sha_config_begin(v); mesh_view_set_u32(v, SHA_V_HEADER + 68, arg); sha_header_changed(v); sha_config_end(v, g); ok = true; break;
732        default: break; /* OP_CHUNK: refused */
733        }
734        return ok ? MESH_R_NONE : MESH_R_BAD_OP;
735    }
736    return MESH_R_BAD_OP;
737}
738
739MESH_PROGRAM(sha_init, sha_task);