From a29c3ac5c38a6f36957f3beb9c63b73c5a867687 Mon Sep 17 00:00:00 2001 From: tromp Date: Mon, 17 Oct 2016 14:52:30 -0400 Subject: [PATCH] refactor types and reduce buckets from 2^16 to 2^12 --- Makefile | 9 +- equi_miner.h | 356 ++++++++++++++------------ hide/equi_miner.h | 619 ---------------------------------------------- 3 files changed, 209 insertions(+), 775 deletions(-) delete mode 100644 hide/equi_miner.h diff --git a/Makefile b/Makefile index 9026d75..8c81810 100644 --- a/Makefile +++ b/Makefile @@ -11,13 +11,16 @@ equi1: equi.h equi_miner.h equi_miner.cpp Makefile $(GPP) equi_miner.cpp blake/blake2b.cpp -o equi1 equi1g: equi.h equi_miner.h equi_miner.cpp Makefile - g++ -g -DSPARK equi_miner.cpp blake/blake2b.cpp -pthread -o equi1g + g++ -g -DLOGSPARK -DSPARKSCALE=11 equi_miner.cpp blake/blake2b.cpp -pthread -o equi1g equi965: equi.h equi_miner.h equi_miner.cpp Makefile $(GPP) -DWN=96 -DWK=5 equi_miner.cpp blake/blake2b.cpp -o equi965 equi1445: equi.h equi_miner.h equi_miner.cpp Makefile - $(GPP) -DWN=144 -DWK=5 -DXWITHASH equi_miner.cpp blake/blake2b.cpp -o equi1445 + $(GPP) -DWN=144 -DWK=5 equi_miner.cpp blake/blake2b.cpp -o equi1445 + +dev1: equi.h dev_miner.h dev_miner.cpp Makefile + $(GPP) -DRESTBITS=8 dev_miner.cpp blake/blake2b.cpp -o dev1 eqcuda: equi_miner.cu equi.h blake2b.cu Makefile nvcc -arch sm_35 equi_miner.cu blake/blake2b.cpp -o eqcuda @@ -32,7 +35,7 @@ verify: equi.h equi.c Makefile g++ -g equi.c blake/blake2b.cpp -o verify bench: equi1 - time ./equi1 -n 1000 -r 100 + time ./equi1 -r 10 test: equi verify Makefile time ./equi -h "" -n 0 -t 1 -s | grep ^Sol | ./verify -h "" -n 0 diff --git a/equi_miner.h b/equi_miner.h index 537c9d5..797077d 100644 --- a/equi_miner.h +++ b/equi_miner.h @@ -24,6 +24,7 @@ #include #include +typedef uint16_t u16; typedef uint64_t u64; #ifdef ATOMIC @@ -34,7 +35,7 @@ typedef u32 au32; #endif #ifndef RESTBITS -#define RESTBITS 4 +#define RESTBITS 8 #endif // 2_log of number of buckets @@ -47,7 +48,7 @@ static const u32 SLOTBITS = RESTBITS+1+1; // number of slots per bucket static const u32 NSLOTS = 1<= 16); // ensures hashes shorten by 1 unit every 2 digits - digit *heap[2]; - for (u32 i =0; i < 2; i++) - heap[i] = (digit *)alloc(1 + htunits(hashsize(i)), sizeof(digit)); + heap0 = (u32 *)alloc(1, sizeof(digit0)); + heap1 = (u32 *)alloc(1, sizeof(digit1)); for (int r=0; r indices[size]) { + for (u32 i=0; i < size; i++) { + const u32 tmp = indices[i]; + indices[i] = indices[size+i]; + indices[size+i] = tmp; + } + } + } + void listindices0(u32 r, const tree t, u32 *indices) { if (r == 0) { *indices = t.getindex(); return; } - const htunit *bt = hta.getbucket(--r,t.bucketid); + const bucket1 &buck = hta.trees1[--r/2][t.bucketid]; const u32 size = 1 << r; u32 *indices1 = indices + size; - listindices(r, bt[t.slotid0 * hta.slotsize(r)].attr, indices); - listindices(r, bt[t.slotid1 * hta.slotsize(r)].attr, indices1); - if (*indices > *indices1) { - for (u32 i=0; i < size; i++) { - const u32 tmp = indices[i]; - indices[i] = indices1[i]; - indices1[i] = tmp; - } - } + listindices1(r, buck[t.slotid0].attr, indices); + listindices1(r, buck[t.slotid1].attr, indices1); + orderindices(indices, size); + } + void listindices1(u32 r, const tree t, u32 *indices) { + const bucket0 &buck = hta.trees0[--r/2][t.bucketid]; + const u32 size = 1 << r; + u32 *indices1 = indices + size; + listindices0(r, buck[t.slotid0].attr, indices); + listindices0(r, buck[t.slotid1].attr, indices1); + orderindices(indices, size); } void candidate(const tree t) { proof prf; - listindices(WK, t, prf); + listindices1(WK, t, prf); // assume WK odd qsort(prf, PROOFSIZE, sizeof(u32), &compu32); for (u32 i=1; i> (SLOTBITS-6); + binsizes[bsize]++; } - for (u32 i=0; i<=NSLOTS; i++) { + for (u32 i=0; i < 65; i++) { #ifdef HIST - printf(" %d:%d", i, bsizes[i]); + printf(" %d:%d", i, binsizes[i]); #else - printf("\342\226%c", '\201'+bsizes[i]/SPARKSCALE); +#ifdef SPARK + u32 sparks = binsizes[i] / SPARKSCALE; +#else + u32 sparks = 0; + for (u32 bs = binsizes[i]; bs; bs >>= 1) sparks++; + sparks = sparks * 7 / SPARKSCALE; +#endif + printf("\342\226%c", '\201' + sparks); #endif } printf("\n"); @@ -263,58 +276,64 @@ struct equi { struct htlayout { htalloc hta; - u32 prevhtunits; - u32 nexthtunits; - u32 prevslotunits; - u32 nextslotunits; + u32 prevhashunits; + u32 nexthashunits; u32 dunits; u32 prevbo; u32 nextbo; - htunit *buck; - htunit *hashbase; - htlayout(equi *eq, u32 r): hta(eq->hta), prevhtunits(0), prevslotunits(0), dunits(0) { + htlayout(equi *eq, u32 r): hta(eq->hta), prevhashunits(0), dunits(0) { u32 nexthashbytes = hashsize(r); - nexthtunits = htunits(nexthashbytes); - nextslotunits = 1 + htunits(hashsize(r&1)); + nexthashunits = hashwords(nexthashbytes); prevbo = 0; - nextbo = nexthtunits * sizeof(htunit) - nexthashbytes; // 0-3 + nextbo = nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3 if (r) { u32 prevhashbytes = hashsize(r-1); - prevhtunits = htunits(prevhashbytes); - prevslotunits = 1 + htunits(hashsize((r-1)&1)); - prevbo = prevhtunits * sizeof(htunit) - prevhashbytes; // 0-3 - dunits = prevhtunits - nexthtunits; + prevhashunits = hashwords(prevhashbytes); + prevbo = prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3 + dunits = prevhashunits - nexthashunits; } } - void setbucket(u32 r, u32 bid) { - buck = hta.getbucket(r, bid); - hashbase = buck + 1; - } - u32 getxhash(const u32 slot, const htunit *hash) const { -#ifdef XWITHASH - return hash->bytes[prevbo] & 0xf; + u32 getxhash0(const slot0* pslot) const { +#if WN == 200 && RESTBITS == 4 + return pslot->hash->bytes[prevbo] >> 4; +#elif WN == 200 && RESTBITS == 8 + return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4; +#elif WN == 144 && RESTBITS == 4 + return pslot->hash->bytes[prevbo] & 0xf; #else - return buck[slot * prevslotunits].attr.xhash; +#error non implemented #endif } - bool equal(const htunit *hash0, const htunit *hash1) const { - return hash0[prevhtunits-1].hash == hash1[prevhtunits-1].hash; + u32 getxhash1(const slot1* pslot) const { +#if WN == 200 && RESTBITS == 4 + return pslot->hash->bytes[prevbo] & 0xf; +#elif WN == 200 && RESTBITS == 8 + return pslot->hash->bytes[prevbo]; +#elif WN == 144 && RESTBITS == 4 + return pslot->hash->bytes[prevbo] & 0xf; +#else +#error non implemented +#endif } - htunit *addtree(u32 r, tree t, u32 bid, u32 slot) { - htunit *buck = hta.getbucket(r,bid); - htunit *slotree = buck + slot * nextslotunits; - slotree->attr = t; - return slotree + 1; + bool equal(const hashunit *hash0, const hashunit *hash1) const { + return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word; } }; struct collisiondata { #ifdef XBITMAP +#if NSLOTS > 64 +#error cant use XBITMAP with more than 64 slots +#endif u64 xhashmap[NRESTS]; u64 xmap; #else +#if RESTBITS <= 6 typedef uchar xslot; +#else + typedef u16 xslot; +#endif xslot nxhashslots[NRESTS]; xslot xhashslots[NRESTS][XFULL]; xslot *xx; @@ -371,102 +390,134 @@ struct equi { const u32 hashbytes = hashsize(0); for (u32 block = id; block < NBLOCKS; block += nthreads) { state = blake_ctx; - const u32 leb = htole32(block); + u32 leb = htole32(block); blake2b_update(&state, (uchar *)&leb, sizeof(u32)); blake2b_final(&state, hash, HASHOUT); for (u32 i = 0; i> 4; -#endif +#elif BUCKBITS == 12 && RESTBITS == 8 + const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4; #elif BUCKBITS == 20 && RESTBITS == 4 const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4; -#ifndef XWITHASH - const u32 xhash = ph[2] & 0xf; -#endif #elif BUCKBITS == 12 && RESTBITS == 4 const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4; const u32 xhash = ph[1] & 0xf; #else #error not implemented #endif - const u32 slot = findslot(0, bucketid); + const u32 slot = getslot(0, bucketid); if (slot >= NSLOTS) { bfull++; continue; } tree leaf; leaf.setindex(block*HASHESPERBLAKE+i); -#ifndef XWITHASH - leaf.xhash = xhash; -#endif - htunit *dest = htl.addtree(0, leaf, bucketid, slot); - memcpy(dest->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); + slot0 &s = hta.trees0[0][bucketid][slot]; + s.attr = leaf; + memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); } } } - void digitr(const u32 r, const u32 id) { + void digitodd(const u32 r, const u32 id) { htlayout htl(this, r); collisiondata cd; for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { cd.clear(); - htl.setbucket(r-1, bucketid); - u32 bsize = getnslots(r-1, bucketid); + slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?! + u32 bsize = getnslots(r-1, bucketid); // optimize by putting bucketsize with block?! for (u32 s1 = 0; s1 < bsize; s1++) { - const htunit *hash1 = htl.hashbase + s1 * htl.prevslotunits; - if (!cd.addslot(s1, htl.getxhash(s1, hash1))) { + const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! + if (!cd.addslot(s1, htl.getxhash0(pslot1))) { xfull++; continue; } for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - const htunit *hash0 = htl.hashbase + s0 * htl.prevslotunits; - if (htl.equal(hash0, hash1)) { + const slot0 *pslot0 = buck + s0; + if (htl.equal(pslot0->hash, pslot1->hash)) { hfull++; continue; } u32 xorbucketid; - u32 xhash; -#if BUCKBITS == 16 && RESTBITS == 4 -#ifdef XWITHASH - xhash = hash0->bytes[htl.prevbo+2] ^ hash1->bytes[htl.prevbo+2]; -#error not yet implemented -#else - xorbucketid = ((u32)(hash0->bytes[htl.prevbo]^hash1->bytes[htl.prevbo]) << 8) - | (hash0->bytes[htl.prevbo+1]^hash1->bytes[htl.prevbo+1]); - xhash = hash0->bytes[htl.prevbo+2] ^ hash1->bytes[htl.prevbo+2]; - if (r&1) { - xorbucketid = ((xorbucketid & 0xfff) << 4) | (xhash >> 4); - xhash &= 0xf; - } else xhash >>= 4; -#endif -#elif BUCKBITS == 20 && RESTBITS == 4 && defined XWITHASH - xhash = hash0->bytes[htl.prevbo+3] ^ hash1->bytes[htl.prevbo+3]; - xorbucketid = ((((u32)(hash0->bytes[htl.prevbo+1]^hash1->bytes[htl.prevbo+1]) << 8) | (hash0->bytes[htl.prevbo+2]^hash1->bytes[htl.prevbo+2])) << 4) | xhash >> 4; - xhash &= 0xf; -#elif BUCKBITS == 12 && RESTBITS == 4 - xhash = hash0->bytes[htl.prevbo+1] ^ hash1->bytes[htl.prevbo+1]; - xorbucketid = ((u32)(hash0->bytes[htl.prevbo]^hash1->bytes[htl.prevbo]) << 4) | xhash >> 4; - xhash &= 0xf; + const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; +#if WN == 200 && BUCKBITS == 12 && RESTBITS == 8 + xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8) + | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]); +#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 + xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) + | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) + | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; +#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 + xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) + | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; #else #error not implemented #endif - const u32 xorslot = findslot(r, xorbucketid); + const u32 xorslot = getslot(r, xorbucketid); if (xorslot >= NSLOTS) { bfull++; continue; } tree xort; xort.bucketid = bucketid; xort.slotid0 = s0; xort.slotid1 = s1; -#ifndef XWITHASH - xort.xhash = xhash; + slot1 &xs = htl.hta.trees1[r/2][xorbucketid][xorslot]; + xs.attr = xort; + for (u32 i=htl.dunits; i < htl.prevhashunits; i++) + xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; + } + } + } + } + + void digiteven(const u32 r, const u32 id) { + htlayout htl(this, r); + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS + u32 bsize = getnslots(r-1, bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS + if (!cd.addslot(s1, htl.getxhash1(pslot1))) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const slot1 *pslot0 = buck + s0; + if (htl.equal(pslot0->hash, pslot1->hash)) { + hfull++; + continue; + } + u32 xorbucketid; + const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; +#if WN == 200 && BUCKBITS == 12 && RESTBITS == 8 + xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) + | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; +#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 + xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) + | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) + | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; +#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 + xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) + | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; +#else +#error not implemented #endif - htunit *xorhash = htl.addtree(r, xort, xorbucketid, xorslot); - for (u32 i=htl.dunits; i < htl.prevhtunits; i++) - xorhash[i-htl.dunits].hash = hash0[i].hash ^ hash1[i].hash; + const u32 xorslot = getslot(r, xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + tree xort; xort.bucketid = bucketid; + xort.slotid0 = s0; xort.slotid1 = s1; + slot0 &xs = htl.hta.trees0[r/2][xorbucketid][xorslot]; + xs.attr = xort; + for (u32 i=htl.dunits; i < htl.prevhashunits; i++) + xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; } } } @@ -477,16 +528,16 @@ struct equi { htlayout htl(this, WK); for (u32 bucketid = id; bucketid < NBUCKETS; bucketid += nthreads) { cd.clear(); - htl.setbucket(WK-1, bucketid); + slot0 *buck = htl.hta.trees0[(WK-1)/2][bucketid]; u32 bsize = getnslots(WK-1, bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const htunit *hash1 = htl.hashbase + s1 * htl.prevslotunits; - if (!cd.addslot(s1, htl.getxhash(s1, hash1))) + const slot0 *pslot1 = buck + s1; + if (!cd.addslot(s1, htl.getxhash0(pslot1))) // assume WK odd continue; for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - const htunit *hash0 = htl.hashbase + s0 * htl.prevslotunits; - if (htl.equal(hash0, hash1)) { + const slot0 *pslot0 = buck + s0; + if (htl.equal(pslot0->hash, pslot1->hash)) { tree xort; xort.bucketid = bucketid; xort.slotid0 = s0; xort.slotid1 = s1; candidate(xort); @@ -511,7 +562,6 @@ void barrier(pthread_barrier_t *barry) { } } - void *worker(void *vp) { thread_ctx *tp = (thread_ctx *)vp; equi *eq = tp->eq; @@ -530,7 +580,7 @@ void *worker(void *vp) { if (tp->id == 0) printf("Digit %d", r); barrier(&eq->barry); - eq->digitr(r, tp->id); + r&1 ? eq->digitodd(r, tp->id) : eq->digiteven(r, tp->id); barrier(&eq->barry); if (tp->id == 0) { printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull); diff --git a/hide/equi_miner.h b/hide/equi_miner.h deleted file mode 100644 index f55f801..0000000 --- a/hide/equi_miner.h +++ /dev/null @@ -1,619 +0,0 @@ -// Equihash solver -// Copyright (c) 2016 John Tromp - -// Fix N, K, such that n = N/(k+1) is integer -// Fix M = 2^{n+1} hashes each of length N bits, -// H_0, ... , H_{M-1}, generated fom (n+1)-bit indices. -// Problem: find binary tree on 2^K distinct indices, -// for which the exclusive-or of leaf hashes is all 0s. -// Additionally, it should satisfy the Wagner conditions: -// for each height i subtree, the exclusive-or -// of its 2^i corresponding hashes starts with i*n 0 bits, -// and for i>0 the leftmost leaf of its left subtree -// is less than the leftmost leaf of its right subtree - -// The algorithm below solves this by maintaining the trees -// in a graph of K layers, each split into buckets -// with buckets indexed by the first n-RESTBITS bits following -// the i*n 0s, each bucket having 4 * 2^RESTBITS slots, -// twice the number of subtrees expected to land there. - -#include "equi.h" -#include -#include -#include -#include - -typedef uint64_t u64; - -#ifdef ATOMIC -#include -typedef std::atomic au32; -#else -typedef u32 au32; -#endif - -#ifndef RESTBITS -#define RESTBITS 4 -#endif - -// 2_log of number of buckets -#define BUCKBITS (DIGITBITS-RESTBITS) - -// number of buckets -static const u32 NBUCKETS = 1<> SLOTBITS; - } -}; - -union hashunit { - u32 word; - uchar bytes[sizeof(u32)]; -}; - -#define WORDS(bits) ((bits + 31) / 32) -#ifdef XINTREE -#define HASHWORDS0 WORDS(WN - DIGITBITS) -#define HASHWORDS1 WORDS(WN - 2*DIGITBITS) -#else -#define HASHWORDS0 WORDS(WN - DIGITBITS + RESTBITS) -#define HASHWORDS1 WORDS(WN - 2*DIGITBITS + RESTBITS) -#endif - -struct slot0 { - tree attr; - hashunit hash[HASHWORDS0]; -}; - -struct slot1 { - tree attr; - hashunit hash[HASHWORDS1]; -}; - -// a bucket is NSLOTS treenodes -typedef slot0 bucket0[NSLOTS]; -typedef slot0 bucket1[NSLOTS]; // use bigger one for now -// the N-bit hash consists of K+1 n-bit "digits" -// each of which corresponds to a layer of NBUCKETS buckets -typedef bucket0 digit0[NBUCKETS]; -typedef bucket1 digit1[NBUCKETS]; - -// size (in bytes) of hash in round 0 <= r < WK -u32 hashsize(const u32 r) { -#ifdef XINTREE - const u32 hashbits = WN - (r+1) * DIGITBITS; -#else - const u32 hashbits = WN - (r+1) * DIGITBITS + RESTBITS; -#endif - return (hashbits + 7) / 8; -} - -u32 hashwords(u32 bytes) { - return (bytes + 3) / 4; -} - -// manages hash and tree data -struct htalloc { - bucket0 *trees[WK]; - u32 alloced; - htalloc() { - alloced = 0; - } - void alloctrees() { -// optimize xenoncat's fixed memory layout, avoiding any waste -// digit trees hashes trees hashes -// 0 0 A A A A A A . . . . . . -// 1 0 A A A A A A 1 B B B B B -// 2 0 2 C C C C C 1 B B B B B -// 3 0 2 C C C C C 1 3 D D D D -// 4 0 2 4 E E E E 1 3 D D D D -// 5 0 2 4 E E E E 1 3 5 F F F -// 6 0 2 4 6 . G G 1 3 5 F F F -// 7 0 2 4 6 . G G 1 3 5 7 H H -// 8 0 2 4 6 8 . I 1 3 5 7 H H - assert(DIGITBITS >= 16); // ensures hashes shorten by 1 unit every 2 digits - digit0 *heap[2]; - heap[0] = (digit0 *)alloc(1, sizeof(digit0)); - heap[1] = (digit1 *)alloc(1, sizeof(digit0)); // still need to exploit HASHWORDS1 indices[size]) { - for (u32 i=0; i < size; i++) { - const u32 tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } - } - void listindices0(u32 r, const tree t, u32 *indices) { - if (r == 0) { - *indices = t.getindex(); - return; - } - const bucket0 &buck = hta.trees[--r][t.bucketid]; - const u32 size = 1 << r; - u32 *indices1 = indices + size; - listindices1(r, buck[t.slotid0].attr, indices); - listindices1(r, buck[t.slotid1].attr, indices1); - orderindices(indices, size); - } - void listindices1(u32 r, const tree t, u32 *indices) { - const bucket0 &buck = hta.trees[--r][t.bucketid]; - const u32 size = 1 << r; - u32 *indices1 = indices + size; - listindices0(r, buck[t.slotid0].attr, indices); - listindices0(r, buck[t.slotid1].attr, indices1); - orderindices(indices, size); - } - void candidate(const tree t) { - proof prf; - listindices1(WK, t, prf); // assume WK odd - qsort(prf, PROOFSIZE, sizeof(u32), &compu32); - for (u32 i=1; ihta), prevhashunits(0), dunits(0) { - u32 nexthashbytes = hashsize(r); - nexthashunits = hashwords(nexthashbytes); - prevbo = 0; - nextbo = nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3 - if (r) { - u32 prevhashbytes = hashsize(r-1); - prevhashunits = hashwords(prevhashbytes); - prevbo = prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3 - dunits = prevhashunits - nexthashunits; - } - } - u32 getxhash0(const slot0* pslot) const { -#ifdef XINTREE - return pslot->attr.xhash; -#else - return pslot->hash.bytes[prevbo] >> 4; -#endif - } - u32 getxhash1(const slot0* pslot) const { -#ifdef XINTREE - return pslot->attr.xhash; -#else - return pslot->hash.bytes[prevbo] & 0xf; -#endif - } - bool equal(const hashunit *hash0, const hashunit *hash1) const { - return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word; - } - }; - - struct collisiondata { -#ifdef XBITMAP - u64 xhashmap[NRESTS]; - u64 xmap; -#else - typedef uchar xslot; - xslot nxhashslots[NRESTS]; - xslot xhashslots[NRESTS][XFULL]; - xslot *xx; - u32 n0; - u32 n1; -#endif - u32 s0; - - void clear() { -#ifdef XBITMAP - memset(xhashmap, 0, NRESTS * sizeof(u64)); -#else - memset(nxhashslots, 0, NRESTS * sizeof(xslot)); -#endif - } - bool addslot(u32 s1, u32 xh) { -#ifdef XBITMAP - xmap = xhashmap[xh]; - xhashmap[xh] |= (u64)1 << s1; - s0 = -1; - return true; -#else - n1 = (u32)nxhashslots[xh]++; - if (n1 >= XFULL) - return false; - xx = xhashslots[xh]; - xx[n1] = s1; - n0 = 0; - return true; -#endif - } - bool nextcollision() const { -#ifdef XBITMAP - return xmap != 0; -#else - return n0 < n1; -#endif - } - u32 slot() { -#ifdef XBITMAP - const u32 ffs = __builtin_ffsll(xmap); - s0 += ffs; xmap >>= ffs; - return s0; -#else - return (u32)xx[n0++]; -#endif - } - }; - - void digit0(const u32 id) { - uchar hash[HASHOUT]; - blake2b_state state; - htlayout htl(this, 0); - const u32 hashbytes = hashsize(0); - for (u32 block = id; block < NBLOCKS; block += nthreads) { - state = blake_ctx; - u32 leb = htole32(block); - blake2b_update(&state, (uchar *)&leb, sizeof(u32)); - blake2b_final(&state, hash, HASHOUT); - for (u32 i = 0; i> 4; -#endif -#elif BUCKBITS == 20 && RESTBITS == 4 - const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4; -#ifdef XINTREE - const u32 xhash = ph[2] & 0xf; -#endif -#elif BUCKBITS == 12 && RESTBITS == 4 - const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4; - const u32 xhash = ph[1] & 0xf; -#else -#error not implemented -#endif - const u32 slot = getslot(0, bucketid); - if (slot >= NSLOTS) { - bfull++; - continue; - } - tree leaf; - leaf.setindex(block*HASHESPERBLAKE+i); -#ifdef XINTREE - leaf.xhash = xhash; -#endif - slot0 &s = hta.trees[0][bucketid][slot]; - s.attr = leaf; - memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); - } - } - } - - void digitodd(const u32 r, const u32 id) { - htlayout htl(this, r); - collisiondata cd; - for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { - cd.clear(); - slot0 *buck = htl.hta.trees[r-1][bucketid]; // optimize by updating previous buck?! - u32 bsize = getnslots(r-1, bucketid); // optimize by putting bucketsize with block?! - for (u32 s1 = 0; s1 < bsize; s1++) { - const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! - if (!cd.addslot(s1, htl.getxhash0(pslot1))) { - xfull++; - continue; - } - for (; cd.nextcollision(); ) { - const u32 s0 = cd.slot(); - const slot0 *pslot0 = buck + s0; - if (htl.equal(pslot0->hash, pslot1->hash)) { - hfull++; - continue; - } - u32 xorbucketid; - u32 xhash; -#if BUCKBITS == 16 && RESTBITS == 4 -#ifdef XINTREE - xorbucketid = ((u32)(pslot0->hash->bytes[htl.prevbo]^pslot1->hash->bytes[htl.prevbo]) << 8) - | (pslot0->hash->bytes[htl.prevbo+1]^pslot1->hash->bytes[htl.prevbo+1]); - xhash = pslot0->hash->bytes[htl.prevbo+2] ^ pslot1->hash->bytes[htl.prevbo+2]; - xorbucketid = ((xorbucketid & 0xfff) << 4) | (xhash >> 4); - xhash &= 0xf; -#else - xhash = hash0->bytes[htl.prevbo+2] ^ hash1->bytes[htl.prevbo+2]; -#error not yet implemented -#endif -#elif BUCKBITS == 20 && RESTBITS == 4 && !defined XINTREE - xhash = hash0->bytes[htl.prevbo+3] ^ hash1->bytes[htl.prevbo+3]; - xorbucketid = ((((u32)(hash0->bytes[htl.prevbo+1]^hash1->bytes[htl.prevbo+1]) << 8) | (hash0->bytes[htl.prevbo+2]^hash1->bytes[htl.prevbo+2])) << 4) | xhash >> 4; - xhash &= 0xf; -#elif BUCKBITS == 12 && RESTBITS == 4 - xhash = hash0->bytes[htl.prevbo+1] ^ hash1->bytes[htl.prevbo+1]; - xorbucketid = ((u32)(hash0->bytes[htl.prevbo]^hash1->bytes[htl.prevbo]) << 4) | xhash >> 4; - xhash &= 0xf; -#else -#error not implemented -#endif - const u32 xorslot = getslot(r, xorbucketid); - if (xorslot >= NSLOTS) { - bfull++; - continue; - } - tree xort; xort.bucketid = bucketid; - xort.slotid0 = s0; xort.slotid1 = s1; -#ifdef XINTREE - xort.xhash = xhash; -#endif - slot0 &xs = htl.hta.trees[r][xorbucketid][xorslot]; - xs.attr = xort; - for (u32 i=htl.dunits; i < htl.prevhashunits; i++) - xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } - } - - void digiteven(const u32 r, const u32 id) { - htlayout htl(this, r); - collisiondata cd; - for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { - cd.clear(); - slot0 *buck = htl.hta.trees[r-1][bucketid]; // optimize by updating previous buck?! - u32 bsize = getnslots(r-1, bucketid); // optimize by putting bucketsize with block?! - for (u32 s1 = 0; s1 < bsize; s1++) { - const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! - if (!cd.addslot(s1, htl.getxhash1(pslot1))) { - xfull++; - continue; - } - for (; cd.nextcollision(); ) { - const u32 s0 = cd.slot(); - const slot0 *pslot0 = buck + s0; - if (htl.equal(pslot0->hash, pslot1->hash)) { - hfull++; - continue; - } - u32 xorbucketid; - u32 xhash; -#if BUCKBITS == 16 && RESTBITS == 4 -#ifdef XINTREE - xorbucketid = ((u32)(pslot0->hash->bytes[htl.prevbo]^pslot1->hash->bytes[htl.prevbo]) << 8) - | (pslot0->hash->bytes[htl.prevbo+1]^pslot1->hash->bytes[htl.prevbo+1]); - xhash = (pslot0->hash->bytes[htl.prevbo+2] ^ pslot1->hash->bytes[htl.prevbo+2]) >> 4; -#else - xhash = hash0->bytes[htl.prevbo+2] ^ hash1->bytes[htl.prevbo+2]; -#error not yet implemented -#endif -#elif BUCKBITS == 20 && RESTBITS == 4 && !defined XINTREE - xhash = hash0->bytes[htl.prevbo+3] ^ hash1->bytes[htl.prevbo+3]; - xorbucketid = ((((u32)(hash0->bytes[htl.prevbo+1]^hash1->bytes[htl.prevbo+1]) << 8) | (hash0->bytes[htl.prevbo+2]^hash1->bytes[htl.prevbo+2])) << 4) | xhash >> 4; - xhash &= 0xf; -#elif BUCKBITS == 12 && RESTBITS == 4 - xhash = hash0->bytes[htl.prevbo+1] ^ hash1->bytes[htl.prevbo+1]; - xorbucketid = ((u32)(hash0->bytes[htl.prevbo]^hash1->bytes[htl.prevbo]) << 4) | xhash >> 4; - xhash &= 0xf; -#else -#error not implemented -#endif - const u32 xorslot = getslot(r, xorbucketid); - if (xorslot >= NSLOTS) { - bfull++; - continue; - } - tree xort; xort.bucketid = bucketid; - xort.slotid0 = s0; xort.slotid1 = s1; -#ifdef XINTREE - xort.xhash = xhash; -#endif - slot0 &xs = htl.hta.trees[r][xorbucketid][xorslot]; - xs.attr = xort; - for (u32 i=htl.dunits; i < htl.prevhashunits; i++) - xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } - } - - void digitK(const u32 id) { - collisiondata cd; - htlayout htl(this, WK); - for (u32 bucketid = id; bucketid < NBUCKETS; bucketid += nthreads) { - cd.clear(); - slot0 *buck = htl.hta.trees[WK-1][bucketid]; - u32 bsize = getnslots(WK-1, bucketid); - for (u32 s1 = 0; s1 < bsize; s1++) { - const slot0 *pslot1 = buck + s1; - if (!cd.addslot(s1, htl.getxhash0(pslot1))) // assume WK odd - continue; - for (; cd.nextcollision(); ) { - const u32 s0 = cd.slot(); - const slot0 *pslot0 = buck + s0; - if (htl.equal(pslot0->hash, pslot1->hash)) { - tree xort; xort.bucketid = bucketid; - xort.slotid0 = s0; xort.slotid1 = s1; - candidate(xort); - } - } - } - } - } -}; - -typedef struct { - u32 id; - pthread_t thread; - equi *eq; -} thread_ctx; - -void barrier(pthread_barrier_t *barry) { - const int rc = pthread_barrier_wait(barry); - if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) { - printf("Could not wait on barrier\n"); - pthread_exit(NULL); - } -} - -void *worker(void *vp) { - thread_ctx *tp = (thread_ctx *)vp; - equi *eq = tp->eq; - - if (tp->id == 0) - printf("Digit 0\n"); - barrier(&eq->barry); - eq->digit0(tp->id); - barrier(&eq->barry); - if (tp->id == 0) { - eq->xfull = eq->bfull = eq->hfull = 0; - eq->showbsizes(0); - } - barrier(&eq->barry); - for (u32 r = 1; r < WK; r++) { - if (tp->id == 0) - printf("Digit %d", r); - barrier(&eq->barry); - r&1 ? eq->digitodd(r, tp->id) : eq->digiteven(r, tp->id); - barrier(&eq->barry); - if (tp->id == 0) { - printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull); - eq->xfull = eq->bfull = eq->hfull = 0; - eq->showbsizes(r); - } - barrier(&eq->barry); - } - if (tp->id == 0) - printf("Digit %d\n", WK); - eq->digitK(tp->id); - barrier(&eq->barry); - pthread_exit(NULL); - return 0; -}