dgb-wallet/packages/p2p/native/dgbpow.c
Digibyte.X 93cd8b4bf4 daemon: verify proof-of-work on every synced header; fork choice by work
DigiByte is multi-algorithm, so this brings in six hash functions:
SHA256d and Scrypt in JS, and Qubit, Skein, Groestl and Odocrypt from
DigiByte Core's own C sources compiled to WebAssembly (packages/p2p/native,
emscripten via docker). Each header is checked against its nBits target and
the network powLimit before it can enter the chain; a peer serving an
invalid or future-dated header is benched. Competing branches are accepted
only when they carry more accumulated work than what they replace.

npm run pow:test -w @dgb-wallet/p2p verifies real mainnet headers of all
six algorithms and that a tampered header fails.
2026-10-02 18:37:31 +02:00

73 lines
3 KiB
C

// DigiByte multi-algo proof-of-work hashes, compiled to WebAssembly.
//
// Thin C wrapper over DigiByte Core's own implementations (src/crypto in
// DigiByte-Core/digibyte, copied verbatim into ./src): sphlib Luffa,
// CubeHash, SHAvite, SIMD, Echo, Skein, Groestl, plus Odocrypt and its
// Keccak-p[800] permutation. SHA256d and Scrypt are done in JS
// (@noble/hashes) and are not here.
//
// Interface is deliberately pointer-free for the caller: fixed static
// buffers, the JS side copies 80 bytes in, calls one function, copies the
// digest out. No malloc, no libc I/O, no imports.
//
// in_ptr() → address of the 80-byte header buffer
// out_ptr() → address of the 64-byte output buffer
// hash_qubit() → 32 bytes written to out (Luffa→CubeHash→SHAvite→SIMD→Echo, trim 256)
// hash_skein512() → 64 bytes written to out (caller SHA256s them: Core's HashSkein)
// hash_groestl512() → 64 bytes written to out (caller SHA256s them: Core's HashGroestl)
// hash_odo(key) → 32 bytes written to out (OdoCrypt(key) + Keccak-p[800,12], per hashodo.h)
//
// Build: see build.sh (emscripten in docker).
#include <stdint.h>
#include <string.h>
#include "src/sph_luffa.h"
#include "src/sph_cubehash.h"
#include "src/sph_shavite.h"
#include "src/sph_simd.h"
#include "src/sph_echo.h"
#include "src/sph_skein.h"
#include "src/sph_groestl.h"
#define EXPORT __attribute__((used, visibility("default")))
static unsigned char g_in[80];
static unsigned char g_out[64];
EXPORT unsigned char* in_ptr(void) { return g_in; }
EXPORT unsigned char* out_ptr(void) { return g_out; }
EXPORT void hash_qubit(void) {
unsigned char h[64];
sph_luffa512_context luffa; sph_cubehash512_context cube; sph_shavite512_context shavite;
sph_simd512_context simd; sph_echo512_context echo;
sph_luffa512_init(&luffa); sph_luffa512(&luffa, g_in, 80); sph_luffa512_close(&luffa, h);
sph_cubehash512_init(&cube); sph_cubehash512(&cube, h, 64); sph_cubehash512_close(&cube, h);
sph_shavite512_init(&shavite); sph_shavite512(&shavite, h, 64); sph_shavite512_close(&shavite, h);
sph_simd512_init(&simd); sph_simd512(&simd, h, 64); sph_simd512_close(&simd, h);
sph_echo512_init(&echo); sph_echo512(&echo, h, 64); sph_echo512_close(&echo, h);
memcpy(g_out, h, 32);
}
EXPORT void hash_skein512(void) {
sph_skein512_context c;
sph_skein512_init(&c); sph_skein512(&c, g_in, 80); sph_skein512_close(&c, g_out);
}
EXPORT void hash_groestl512(void) {
sph_groestl512_context c;
sph_groestl512_init(&c); sph_groestl512(&c, g_in, 80); sph_groestl512_close(&c, g_out);
}
// Implemented in odo_glue.cpp (OdoCrypt and the Keccak permutation are
// C++ in Core's tree): OdoCrypt(key).Encrypt + KeccakP800_Permute_12rounds
// over a 100-byte state, per hashodo.h.
void odo_hash(uint32_t key, char* state100);
EXPORT void hash_odo(uint32_t key) {
char cipher[100];
memset(cipher, 0, sizeof cipher);
memcpy(cipher, g_in, 80);
cipher[80] = 1;
odo_hash(key, cipher);
memcpy(g_out, cipher, 32);
}