==> src/sha_verify.c <==1/* sha-verify: re-hashes sha256d's shares on the CPU (kcheck's S checks, run continuously beside
2 * the GPU), from alpha-rust-mesh programs/sha-verify/wasm. Each periodic task reads sha256d's view
3 * through `reads`, and for every share number past the last one checked takes its ring entry
4 * (nonce, ntime, number, zbits, hash), recomputes the header's sha256d with mesh-ref, and counts
5 * it verified when the hashes are equal and the hash is at most the target, else bad.
6 * Configuration changes (sha256d's `gen`, odd while written) restart the count; a share that left
7 * the 32-entry ring before its check is `missed`. The ring entry is read twice: one that a node
8 * rewrote meanwhile is checked at the next task. */
9#include "mesh/ref/sha256d.h"
10#include "mesh/rt_wasm.h"
11
12/* sha256d's view (programs/sha256d V_*). */
13#define S_GEN 0x004u
14#define S_SHARES 0x02cu
15#define S_HEADER 0x080u
16#define S_TARGET 0x0d0u
17#define S_RING 0x200u
18#define RING 32u
19#define RING_BYTES 48u
20
21#define V_VERIFIED 0x00u
22#define V_BAD 0x04u
23#define V_MISSED 0x08u
24#define V_CHECKED 0x0cu
25#define V_GEN 0x10u
26#define V_LAST_NONCE 0x14u
27
28static void init(const mesh_ctx *ctx) { (void)ctx; }
29
30static uint32_t w32(const uint8_t *x, uint32_t i) {
31 return (uint32_t)x[4 * i] | (uint32_t)x[4 * i + 1] << 8 | (uint32_t)x[4 * i + 2] << 16 | (uint32_t)x[4 * i + 3] << 24;
32}
33
34static uint32_t check(const mesh_ctx *ctx) {
35 uint32_t s;
36 mesh_view v;
37 if (!mesh_ctx_find(ctx, "sha256d", 7, &s) || !mesh_ctx_peer_view(ctx, s, &v)) return 0;
38 uint32_t gen = mesh_view_u32(v, S_GEN);
39 if (gen & 1) return 0;
40 uint32_t shares = mesh_view_u32(v, S_SHARES);
41 uint32_t done = mesh_ctx_view_u32(ctx, V_CHECKED);
42 if (gen != mesh_ctx_view_u32(ctx, V_GEN) || shares < done) {
43 done = 0;
44 mesh_ctx_set_u32(ctx, V_GEN, gen);
45 }
46 uint8_t hdr[80], target[32];
47 mesh_view_read(v, S_HEADER, hdr, sizeof hdr);
48 mesh_view_read(v, S_TARGET, target, sizeof target);
49 uint32_t ok = 0, bad = 0, missed = 0;
50 while (done < shares) {
51 uint32_t n = done; /* share number n (0-based) is ring entry n mod RING, its field n + 1 */
52 if (shares - n > RING) {
53 missed++;
54 done++;
55 continue;
56 }
57 uint32_t e = S_RING + (n % RING) * RING_BYTES;
58 uint8_t a[48], b[48];
59 mesh_view_read(v, e, a, sizeof a);
60 mesh_view_read(v, e, b, sizeof b);
61 bool same = true;
62 for (int i = 0; i < 48; i++) same = same && a[i] == b[i];
63 if (!same || w32(a, 2) != n + 1u) break;
64 uint8_t h[32];
65 mesh_sha_hash_at(hdr, w32(a, 0), w32(a, 1), h);
66 bool eq = true;
67 for (int i = 0; i < 32; i++) eq = eq && h[i] == a[16 + i];
68 if (eq && !mesh_sha_le_lt(target, h)) ok++;
69 else bad++;
70 mesh_ctx_set_u32(ctx, V_LAST_NONCE, w32(a, 0));
71 done++;
72 }
73 /* A configuration change meanwhile: these were checked against another header; count none. */
74 if (mesh_view_u32(v, S_GEN) != gen) return 0;
75 mesh_ctx_set_u32(ctx, V_CHECKED, done);
76 const uint32_t offs[3] = {V_VERIFIED, V_BAD, V_MISSED}, xs[3] = {ok, bad, missed};
77 for (uint32_t c = 0; c < 3; c++) {
78 if (xs[c] > 0) {
79 mesh_ctx_set_u32(ctx, offs[c], mesh_ctx_view_u32(ctx, offs[c]) + xs[c]);
80 mesh_ctx_count(ctx, c, xs[c]);
81 }
82 }
83 return ok;
84}
85
86static uint32_t task(const mesh_ctx *ctx, uint32_t op, uint32_t arg) {
87 (void)arg;
88 return op == MESH_OP_TASK ? check(ctx) : MESH_R_BAD_OP;
89}
90
91MESH_PROGRAM(init, task)