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.
73 lines
3 KiB
C
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);
|
|
}
|