skip to content
==> 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)