From 11e1bed4eae51085b884a85c1c57b7cb1b5b0882 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Sat, 22 Oct 2016 22:06:52 -0400 Subject: [PATCH] tiny changes --- dev_miner.h | 105 ++++++-- equi_dev_miner.h | 683 +++++++++++++++++++++++++++++++++++++---------- equi_miner.cpp | 5 +- equi_miner.h | 54 +--- 4 files changed, 633 insertions(+), 214 deletions(-) diff --git a/dev_miner.h b/dev_miner.h index 337bce6..8c61b76 100644 --- a/dev_miner.h +++ b/dev_miner.h @@ -18,7 +18,7 @@ // the i*n 0s, each bucket having 4 * 2^RESTBITS slots, // twice the number of subtrees expected to land there. -#include "dev.h" +#include "equi.h" #include #include #include @@ -72,7 +72,7 @@ static const u32 XFULL = 16; static const u32 SLOTMASK = SLOTRANGE-1; // number of possible values of xhash (rest of n) bits static const u32 NRESTS = 1< indices[size]) { + for (u32 i=0; i < size; i++) { + const u32 tmp = indices[i]; + indices[i] = indices[size+i]; + indices[size+i] = tmp; + } + } + return false; + } + // if dupes != 0, list indices in arbitrary order and return true if dupe found + // if dupes == 0, order indices as in Wagner condition + bool listindices0(u32 r, const tree t, u32 *indices, u32 *dupes) { + if (r == 0) { + u32 idx = t.getindex(); + if (dupes) { + u32 bin = idx & (PROOFSIZE-1); + if (idx == dupes[bin]) return true; + dupes[bin] = idx; + } + *indices = idx; + return false; + } + const slot1 *buck = hta.heap1[t.bucketid()]; + const u32 size = 1 << --r; + u32 tagi = r/2; + return listindices1(r, buck[t.slotid0()][tagi].tag, indices, dupes) + || listindices1(r, buck[t.slotid1()][tagi].tag, indices+size, dupes) + || (!dupes && orderindices(indices, size)); + } + bool listindices1(u32 r, const tree t, u32 *indices, u32 *dupes) { + const slot0 *buck = hta.heap0[t.bucketid()]; + const u32 size = 1 << --r; + u32 tagi = r/2; + return listindices0(r, buck[t.slotid0()][tagi].tag, indices, dupes) + || listindices0(r, buck[t.slotid1()][tagi].tag, indices+size, dupes) + || (!dupes && orderindices(indices, size)); + } + void candidate(const tree t) { + proof prf, dupes; + memset(dupes, 0xffff, sizeof(proof)); + if (listindices1(WK, t, prf, dupes)) return; // assume WK odd + qsort(prf, PROOFSIZE, sizeof(u32), &compu32); + for (u32 i=1; i> 4; +#elif BUCKBITS == 16 && RESTBITS == 4 + const u32 bucketid = ((u32)ph[0] << 8) | ph[1]; #elif BUCKBITS == 11 && RESTBITS == 9 const u32 bucketid = ((u32)ph[0] << 3) | ph[1] >> 5; #elif BUCKBITS == 20 && RESTBITS == 4 @@ -479,9 +532,9 @@ struct equi { bfull++; continue; } - htunit *s = hta.heap0[bucketid][slot] + htl.nexthtunits; - memcpy(s->bytes-hashbytes, ph+WN/8-hashbytes, hashbytes); + htunit *s = hta.heap0[bucketid][slot]; s->tag = tree(block * HASHESPERBLAKE + i); + memcpy(s[1 + htl.nexthtunits].bytes-hashbytes, ph+WN/8-hashbytes, hashbytes); } } } @@ -494,14 +547,14 @@ struct equi { slot0 *buck = htl.hta.heap0[bucketid]; u32 bsize = getnslots0(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const htunit *slot1 = buck[s1]; + const htunit *slot1 = buck[s1]+r/2+1; if (!cd.addslot(s1, htl.getxhash0(slot1))) { xfull++; continue; } for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - const htunit *slot0 = buck[s0]; + const htunit *slot0 = buck[s0]+r/2+1; if (htl.equal(slot0, slot1)) { hfull++; continue; @@ -529,10 +582,10 @@ struct equi { bfull++; continue; } - htunit *xs = htl.hta.heap1[xorbucketid][xorslot]; + htunit *xs = htl.hta.heap1[xorbucketid][xorslot]+r/2; + xs++->tag = tree(bucketid, s0, s1); for (u32 i=htl.dunits; i < htl.prevhtunits; i++) xs++->word = slot0[i].word ^ slot1[i].word; - xs->tag = tree(bucketid, s0, s1); } } } @@ -546,14 +599,14 @@ struct equi { slot1 *buck = htl.hta.heap1[bucketid]; u32 bsize = getnslots1(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const htunit *slot1 = buck[s1]; + const htunit *slot1 = buck[s1]+(r-1)/2+1; if (!cd.addslot(s1, htl.getxhash1(slot1))) { xfull++; continue; } for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - const htunit *slot0 = buck[s0]; + const htunit *slot0 = buck[s0]+(r-1)/2+1; if (htl.equal(slot0, slot1)) { hfull++; continue; @@ -581,10 +634,10 @@ struct equi { bfull++; continue; } - htunit *xs = htl.hta.heap0[xorbucketid][xorslot]; + htunit *xs = htl.hta.heap0[xorbucketid][xorslot]+r/2; + xs++->tag = tree(bucketid, s0, s1); for (u32 i=htl.dunits; i < htl.prevhtunits; i++) xs++->word = slot0[i].word ^ slot1[i].word; - xs->tag = tree(bucketid, s0, s1); } } } @@ -883,12 +936,12 @@ struct equi { slot0 *buck = htl.hta.heap0[bucketid]; u32 bsize = getnslots0(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const htunit *slot1 = buck[s1]; + const htunit *slot1 = buck[s1]+WK/2 + 1; if (!cd.addslot(s1, htl.getxhash0(slot1))) // assume WK odd continue; for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - if (htl.equal(buck[s0], slot1)) { // EASY OPTIMIZE + if (htl.equal(buck[s0]+WK/2+1, slot1)) { // EASY OPTIMIZE candidate(tree(bucketid, s0, s1)); nc++; } @@ -924,7 +977,7 @@ void *worker(void *vp) { barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(0); barrier(&eq->barry); -#if WN == 200 && WK == 9 && RESTBITS == 8 +#if WN == 200 && WK == 9 && RESTBITS == 8 && 0 if (tp->id == 0) printf("Digit 1"); barrier(&eq->barry); eq->digit1(tp->id); diff --git a/equi_dev_miner.h b/equi_dev_miner.h index a2b9bdc..994e492 100644 --- a/equi_dev_miner.h +++ b/equi_dev_miner.h @@ -12,7 +12,7 @@ // 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 +// The algorithm below solves this by maintaining the tree // 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, @@ -20,10 +20,14 @@ #include "equi.h" #include -#include #include #include +#if defined __builtin_bswap32 && defined __LITTLE_ENDIAN +#undef htobe32 +#define htobe32(x) __builtin_bswap32(x) +#endif + typedef uint16_t u16; typedef uint64_t u64; @@ -54,6 +58,8 @@ typedef u32 au32; // number of buckets static const u32 NBUCKETS = 1<= 16); // ensures hashes shorten by 1 unit every 2 digits - 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; + } + } + return false; + } + } + // return true if dupe found + bool listindices0(u32 r, const tree t, u32 *indices, u32 *merged) { + if (r == 0) { + *indices = t.getindex(); + return false; + } + const slot1 *buck = hta.heap1[t.bucketid()]; + const u32 size = 1 << --r; + u32 *indices1 = indices + size; + u32 tagi = hashwords(hashsize(r)); + return listindices1(r, buck[t.slotid0()][tagi].tag, indices, merged) + || listindices1(r, buck[t.slotid1()][tagi].tag, indices1, merged) + || orderindices(indices, size, merged); + } + bool listindices1(u32 r, const tree t, u32 *indices, u32 *merged) { + const slot0 *buck = hta.heap0[t.bucketid()]; + const u32 size = 1 << --r; + u32 *indices1 = indices + size; + u32 tagi = hashwords(hashsize(r)); + return listindices0(r, buck[t.slotid0()][tagi].tag, indices, merged) + || listindices0(r, buck[t.slotid1()][tagi].tag, indices1, merged) + || orderindices(indices, size, merged); + } + void candidate(const tree t) { + proof prf, merged; + if (listindices1(WK, t, prf, merged)) return; +#ifdef ATOMIC + u32 soli = std::atomic_fetch_add_explicit(&nsols, 1U, std::memory_order_relaxed); +#else + u32 soli = nsols++; +#endif + if (soli < MAXSOLS) listindices1(WK, t, sols[soli], 0); + } +#else + bool orderindices(u32 *indices, u32 size) { if (indices[0] > indices[size]) { for (u32 i=0; i < size; i++) { const u32 tmp = indices[i]; @@ -254,43 +318,53 @@ struct equi { indices[size+i] = tmp; } } + return false; } - void listindices0(u32 r, const tree t, u32 *indices) { + // if dupes != 0, list indices in arbitrary order and return true if dupe found + // if dupes == 0, order indices as in Wagner condition + bool listindices0(u32 r, const tree t, u32 *indices, u32 *dupes) { if (r == 0) { - *indices = t.getindex(); - return; + u32 idx = t.getindex(); + if (dupes) { + u32 bin = idx & (PROOFSIZE-1); + if (idx == dupes[bin]) return true; + dupes[bin] = idx; + } + *indices = idx; + return false; } - const bucket1 &buck = hta.trees1[--r/2][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); + const slot1 *buck = hta.heap1[t.bucketid()]; + const u32 size = 1 << --r; + u32 tagi = hashwords(hashsize(r)); + return listindices1(r, buck[t.slotid0()][tagi].tag, indices, dupes) + || listindices1(r, buck[t.slotid1()][tagi].tag, indices+size, dupes) + || (!dupes && 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); + bool listindices1(u32 r, const tree t, u32 *indices, u32 *dupes) { + const slot0 *buck = hta.heap0[t.bucketid()]; + const u32 size = 1 << --r; + u32 tagi = hashwords(hashsize(r)); + return listindices0(r, buck[t.slotid0()][tagi].tag, indices, dupes) + || listindices0(r, buck[t.slotid1()][tagi].tag, indices+size, dupes) + || (!dupes && orderindices(indices, size)); } void candidate(const tree t) { - proof prf; - listindices1(WK, t, prf); // assume WK odd + proof prf, dupes; + memset(dupes, 0xffff, sizeof(proof)); + if (listindices1(WK, t, prf, dupes)) return; // assume WK odd qsort(prf, PROOFSIZE, sizeof(u32), &compu32); - for (u32 i=1; ihta), prevhashunits(0), dunits(0) { + htlayout(equi *eq, u32 r): hta(eq->hta), prevhtunits(0), dunits(0) { u32 nexthashbytes = hashsize(r); - nexthashunits = hashwords(nexthashbytes); + nexthtunits = 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; + prevhtunits = hashwords(prevhashbytes); + prevbo = prevhtunits * sizeof(htunit) - prevhashbytes; // 0-3 + dunits = prevhtunits - nexthtunits; } } - u32 getxhash0(const slot0* pslot) const { + u32 getxhash0(const htunit* slot) const { #if WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] >> 4; + return slot->bytes[prevbo] >> 4; #elif WN == 200 && RESTBITS == 8 - return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4; + return (slot->bytes[prevbo] & 0xf) << 4 | slot->bytes[prevbo+1] >> 4; #elif WN == 200 && RESTBITS == 9 - return (pslot->hash->bytes[prevbo] & 0x1f) << 4 | pslot->hash->bytes[prevbo+1] >> 4; + return (slot->bytes[prevbo] & 0x1f) << 4 | slot->bytes[prevbo+1] >> 4; #elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; + return slot->bytes[prevbo] & 0xf; #else #error non implemented #endif } - u32 getxhash1(const slot1* pslot) const { + u32 getxhash1(const htunit* slot) const { #if WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; + return slot->bytes[prevbo] & 0xf; #elif WN == 200 && RESTBITS == 8 - return pslot->hash->bytes[prevbo]; + return slot->bytes[prevbo]; #elif WN == 200 && RESTBITS == 9 - return (pslot->hash->bytes[prevbo]&1) << 8 | pslot->hash->bytes[prevbo+1]; + return (slot->bytes[prevbo]&1) << 8 | slot->bytes[prevbo+1]; #elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; + return slot->bytes[prevbo] & 0xf; #else #error non implemented #endif } - bool equal(const hashunit *hash0, const hashunit *hash1) const { - return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word; + bool equal(const htunit *hash0, const htunit *hash1) const { + return hash0[prevhtunits-1].word == hash1[prevhtunits-1].word; } }; @@ -455,14 +527,14 @@ struct equi { #else #error not implemented #endif - const u32 slot = getslot(0, bucketid); + const u32 slot = getslot0(bucketid); if (slot >= NSLOTS) { bfull++; continue; } - slot0 &s = hta.trees0[0][bucketid][slot]; - s.attr = tree(block * HASHESPERBLAKE + i); - memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); + htunit *s = hta.heap0[bucketid][slot] + htl.nexthtunits; + memcpy(s->bytes-hashbytes, ph+WN/8-hashbytes, hashbytes); + s->tag = tree(block * HASHESPERBLAKE + i); } } } @@ -472,23 +544,23 @@ struct equi { collisiondata cd; for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { cd.clear(); - 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?! + slot0 *buck = htl.hta.heap0[bucketid]; + u32 bsize = getnslots0(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! - if (!cd.addslot(s1, htl.getxhash0(pslot1))) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, htl.getxhash0(slot1))) { xfull++; continue; } for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - const slot0 *pslot0 = buck + s0; - if (htl.equal(pslot0->hash, pslot1->hash)) { + const htunit *slot0 = buck[s0]; + if (htl.equal(slot0, slot1)) { hfull++; continue; } u32 xorbucketid; - const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; + const uchar *bytes0 = slot0->bytes, *bytes1 = slot1->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]); @@ -505,15 +577,15 @@ struct equi { #else #error not implemented #endif - const u32 xorslot = getslot(r, xorbucketid); + const u32 xorslot = getslot1(xorbucketid); if (xorslot >= NSLOTS) { bfull++; continue; } - slot1 &xs = htl.hta.trees1[r/2][xorbucketid][xorslot]; - xs.attr = tree(bucketid, s0, s1); - for (u32 i=htl.dunits; i < htl.prevhashunits; i++) - xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; + htunit *xs = htl.hta.heap1[xorbucketid][xorslot]; + for (u32 i=htl.dunits; i < htl.prevhtunits; i++) + xs++->word = slot0[i].word ^ slot1[i].word; + xs->tag = tree(bucketid, s0, s1); } } } @@ -524,23 +596,23 @@ struct equi { 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); + slot1 *buck = htl.hta.heap1[bucketid]; + u32 bsize = getnslots1(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!cd.addslot(s1, htl.getxhash1(pslot1))) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, htl.getxhash1(slot1))) { xfull++; continue; } for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - const slot1 *pslot0 = buck + s0; - if (htl.equal(pslot0->hash, pslot1->hash)) { + const htunit *slot0 = buck[s0]; + if (htl.equal(slot0, slot1)) { hfull++; continue; } u32 xorbucketid; - const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; + const uchar *bytes0 = slot0->bytes, *bytes1 = slot1->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; @@ -557,15 +629,299 @@ struct equi { #else #error not implemented #endif - const u32 xorslot = getslot(r, xorbucketid); + const u32 xorslot = getslot0(xorbucketid); if (xorslot >= NSLOTS) { bfull++; continue; } - slot0 &xs = htl.hta.trees0[r/2][xorbucketid][xorslot]; - xs.attr = tree(bucketid, s0, s1); - for (u32 i=htl.dunits; i < htl.prevhashunits; i++) - xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; + htunit *xs = htl.hta.heap0[xorbucketid][xorslot]; + for (u32 i=htl.dunits; i < htl.prevhtunits; i++) + xs++->word = slot0[i].word ^ slot1[i].word; + xs->tag = tree(bucketid, s0, s1); + } + } + } + } + + void digit1(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot0 *buck = heaps.heap0[bucketid]; + u32 bsize = getnslots0(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, htobe32(slot1->word) >> 20 & 0xff)) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[5].word == slot1[5].word) { + hfull++; + continue; + } + u32 xorbucketid = htobe32(slot0->word ^ slot1->word) >> 8 & BUCKMASK; + const u32 xorslot = getslot1(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + u64 *x = (u64 *)heaps.heap1[xorbucketid][xorslot]; + u64 *x0 = (u64 *)slot0, *x1 = (u64 *)slot1; + *x++ = x0[0] ^ x1[0]; + *x++ = x0[1] ^ x1[1]; + *x++ = x0[2] ^ x1[2]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit2(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot1 *buck = heaps.heap1[bucketid]; + u32 bsize = getnslots1(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, slot1->bytes[3])) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[5].word == slot1[5].word) { + hfull++; + continue; + } + u32 xorbucketid = htobe32(slot0[1].word ^ slot1[1].word) >> 20; + const u32 xorslot = getslot0(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + htunit *xs = heaps.heap0[xorbucketid][xorslot]; + xs++->word = slot0[1].word ^ slot1[1].word; + u64 *x = (u64 *)xs, *x0 = (u64 *)slot0, *x1 = (u64 *)slot1; + *x++ = x0[1] ^ x1[1]; + *x++ = x0[2] ^ x1[2]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit3(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot0 *buck = heaps.heap0[bucketid]; + u32 bsize = getnslots0(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, htobe32(slot1->word) >> 12 & 0xff)) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[4].word == slot1[4].word) { + hfull++; + continue; + } + u32 xorbucketid = htobe32(slot0[0].word ^ slot1[0].word) & BUCKMASK; + const u32 xorslot = getslot1(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + u64 *x = (u64 *)heaps.heap1[xorbucketid][xorslot]; + u64 *x0 = (u64 *)(slot0+1), *x1 = (u64 *)(slot1+1); + *x++ = x0[0] ^ x1[0]; + *x++ = x0[1] ^ x1[1]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit4(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot1 *buck = heaps.heap1[bucketid]; + u32 bsize = getnslots1(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, slot1->bytes[0])) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[3].word == slot1[3].word) { + hfull++; + continue; + } + u32 xorbucketid = htobe32(slot0[0].word ^ slot1[0].word) >> 12 & BUCKMASK; + const u32 xorslot = getslot0(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + u64 *x = (u64 *)heaps.heap0[xorbucketid][xorslot]; + u64 *x0 = (u64 *)slot0, *x1 = (u64 *)slot1; + *x++ = x0[0] ^ x1[0]; + *x++ = x0[1] ^ x1[1]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit5(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot0 *buck = heaps.heap0[bucketid]; + u32 bsize = getnslots0(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, htobe32(slot1->word) >> 4 & 0xff)) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[3].word == slot1[3].word) { + hfull++; + continue; + } + u32 xor1 = slot0[1].word ^ slot1[1].word; + u32 xorbucketid = (((u32)(slot0->bytes[3] ^ slot1->bytes[3]) & 0xf) + << 8) | (xor1 & 0xff); + const u32 xorslot = getslot1(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + htunit *xs = heaps.heap1[xorbucketid][xorslot]; + xs++->word = xor1; + u64 *x = (u64 *)xs, *x0 = (u64 *)slot0, *x1 = (u64 *)slot1; + *x++ = x0[1] ^ x1[1]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit6(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot1 *buck = heaps.heap1[bucketid]; + u32 bsize = getnslots1(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, slot1->bytes[1])) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[2].word == slot1[2].word) { + hfull++; + continue; + } + u32 xorbucketid = htobe32(slot0[0].word ^ slot1[0].word) >> 4 & BUCKMASK; + const u32 xorslot = getslot0(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + htunit *xs = heaps.heap0[xorbucketid][xorslot]; + xs++->word = slot0[0].word ^ slot1[0].word; + u64 *x = (u64 *)xs, *x0 = (u64 *)(slot0+1), *x1 = (u64 *)(slot1+1); + *x++ = x0[0] ^ x1[0]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit7(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot0 *buck = heaps.heap0[bucketid]; + u32 bsize = getnslots0(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, (slot1->bytes[3] & 0xf) << 4 | slot1->bytes[3+1] >> 4)) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + if (slot0[2].word == slot1[2].word) { + hfull++; + continue; + } + u32 xorbucketid = htobe32(slot0[1].word ^ slot1[1].word) >> 16 & BUCKMASK; + const u32 xorslot = getslot1(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + u64 *x = (u64 *)heaps.heap1[xorbucketid][xorslot]; + u64 *x0 = (u64 *)(slot0+1), *x1 = (u64 *)(slot1+1); + *x++ = x0[0] ^ x1[0]; + ((htunit *)x)->tag = tree(bucketid, s0, s1); + } + } + } + } + void digit8(const u32 id) { + htalloc heaps = hta; + collisiondata cd; + for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) { + cd.clear(); + slot1 *buck = heaps.heap1[bucketid]; + u32 bsize = getnslots1(bucketid); + for (u32 s1 = 0; s1 < bsize; s1++) { + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, slot1->bytes[2])) { + xfull++; + continue; + } + for (; cd.nextcollision(); ) { + const u32 s0 = cd.slot(); + const htunit *slot0 = buck[s0]; + u32 xor1 = slot0[1].word ^ slot1[1].word; + if (!xor1) { + hfull++; + continue; + } + u32 xorbucketid = ((u32)(slot0->bytes[3] ^ slot1->bytes[3]) << 4) + | (xor1 >> 4 & 0xf); + const u32 xorslot = getslot0(xorbucketid); + if (xorslot >= NSLOTS) { + bfull++; + continue; + } + htunit *xs = heaps.heap0[xorbucketid][xorslot]; + xs++->word = xor1; + xs->tag = tree(bucketid, s0, s1); } } } @@ -574,23 +930,25 @@ struct equi { void digitK(const u32 id) { collisiondata cd; htlayout htl(this, WK); -u32 nc = 0; + u32 nc = 0; for (u32 bucketid = id; bucketid < NBUCKETS; bucketid += nthreads) { cd.clear(); - slot0 *buck = htl.hta.trees0[(WK-1)/2][bucketid]; - u32 bsize = getnslots(WK-1, bucketid); + slot0 *buck = htl.hta.heap0[bucketid]; + u32 bsize = getnslots0(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { - const slot0 *pslot1 = buck + s1; - if (!cd.addslot(s1, htl.getxhash0(pslot1))) // assume WK odd + const htunit *slot1 = buck[s1]; + if (!cd.addslot(s1, htl.getxhash0(slot1))) // assume WK odd continue; for (; cd.nextcollision(); ) { const u32 s0 = cd.slot(); - if (htl.equal(buck[s0].hash, pslot1->hash)) -nc++, candidate(tree(bucketid, s0, s1)); + if (htl.equal(buck[s0], slot1)) { // EASY OPTIMIZE + candidate(tree(bucketid, s0, s1)); + nc++; + } } } } -// printf(" %d candidates ", nc); + // printf(" %d candidates ", nc); } }; @@ -613,30 +971,75 @@ void *worker(void *vp) { equi *eq = tp->eq; if (tp->id == 0) - printf("Digit 0\n"); + printf("Digit 0"); barrier(&eq->barry); eq->digit0(tp->id); barrier(&eq->barry); - if (tp->id == 0) { - eq->xfull = eq->bfull = eq->hfull = 0; - eq->showbsizes(0); - } + if (tp->id == 0) eq->showbsizes(0); barrier(&eq->barry); +#if WN == 200 && WK == 9 && RESTBITS == 8 + if (tp->id == 0) printf("Digit 1"); + barrier(&eq->barry); + eq->digit1(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(1); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 2"); + barrier(&eq->barry); + eq->digit2(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(2); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 3"); + barrier(&eq->barry); + eq->digit3(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(3); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 4"); + barrier(&eq->barry); + eq->digit4(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(4); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 5"); + barrier(&eq->barry); + eq->digit5(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(5); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 6"); + barrier(&eq->barry); + eq->digit6(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(6); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 7"); + barrier(&eq->barry); + eq->digit7(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(7); + barrier(&eq->barry); + if (tp->id == 0) printf("Digit 8"); + barrier(&eq->barry); + eq->digit8(tp->id); + barrier(&eq->barry); + if (tp->id == 0) eq->showbsizes(8); + barrier(&eq->barry); +#else 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); - } + if (tp->id == 0) eq->showbsizes(r); barrier(&eq->barry); } +#endif if (tp->id == 0) printf("Digit %d\n", WK); + barrier(&eq->barry); eq->digitK(tp->id); barrier(&eq->barry); pthread_exit(NULL); diff --git a/equi_miner.cpp b/equi_miner.cpp index 72c398f..3b01b30 100644 --- a/equi_miner.cpp +++ b/equi_miner.cpp @@ -65,13 +65,12 @@ int main(int argc, char **argv) { for (unsigned s = 0; s < eq.nsols; s++) { nsols++; if (showsol) { - printf("Solution"); + printf("\nSolution"); for (u32 i = 0; i < PROOFSIZE; i++) printf(" %jx", (uintmax_t)eq.sols[s][i]); - printf("\n"); } } - printf("%d solutions\n", nsols); + printf("\n%d solutions\n", nsols); sumnsols += nsols; } free(threads); diff --git a/equi_miner.h b/equi_miner.h index 994e492..bc9451e 100644 --- a/equi_miner.h +++ b/equi_miner.h @@ -388,6 +388,7 @@ struct equi { } printf("\n"); #endif + printf("Digit %d", r+1); } struct htlayout { @@ -413,8 +414,6 @@ struct equi { return slot->bytes[prevbo] >> 4; #elif WN == 200 && RESTBITS == 8 return (slot->bytes[prevbo] & 0xf) << 4 | slot->bytes[prevbo+1] >> 4; -#elif WN == 200 && RESTBITS == 9 - return (slot->bytes[prevbo] & 0x1f) << 4 | slot->bytes[prevbo+1] >> 4; #elif WN == 144 && RESTBITS == 4 return slot->bytes[prevbo] & 0xf; #else @@ -426,8 +425,6 @@ struct equi { return slot->bytes[prevbo] & 0xf; #elif WN == 200 && RESTBITS == 8 return slot->bytes[prevbo]; -#elif WN == 200 && RESTBITS == 9 - return (slot->bytes[prevbo]&1) << 8 | slot->bytes[prevbo+1]; #elif WN == 144 && RESTBITS == 4 return slot->bytes[prevbo] & 0xf; #else @@ -503,22 +500,20 @@ struct equi { void digit0(const u32 id) { uchar hash[HASHOUT]; - blake2b_state state; + blake2b_state state0 = blake_ctx; htlayout htl(this, 0); const u32 hashbytes = hashsize(0); for (u32 block = id; block < NBLOCKS; block += nthreads) { - state = blake_ctx; + blake2b_state state = state0; u32 leb = htole32(block); blake2b_update(&state, (uchar *)&leb, sizeof(u32)); blake2b_final(&state, hash, HASHOUT); for (u32 i = 0; i> 4; -#elif BUCKBITS == 11 && RESTBITS == 9 - const u32 bucketid = ((u32)ph[0] << 3) | ph[1] >> 5; +#elif BUCKBITS == 16 && RESTBITS == 4 + const u32 bucketid = ((u32)ph[0] << 8) | ph[1]; #elif BUCKBITS == 20 && RESTBITS == 4 const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4; #elif BUCKBITS == 12 && RESTBITS == 4 @@ -564,9 +559,6 @@ struct equi { #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 == 200 && BUCKBITS == 11 && RESTBITS == 9 - xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 7) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 1; #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) @@ -616,9 +608,6 @@ struct equi { #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 == 200 && BUCKBITS == 11 && RESTBITS == 9 - xorbucketid = ((u32)(bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) << 3) - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 5; #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) @@ -866,7 +855,7 @@ struct equi { u32 bsize = getnslots0(bucketid); for (u32 s1 = 0; s1 < bsize; s1++) { const htunit *slot1 = buck[s1]; - if (!cd.addslot(s1, (slot1->bytes[3] & 0xf) << 4 | slot1->bytes[3+1] >> 4)) { + if (!cd.addslot(s1, (slot1->bytes[3] & 0xf) << 4 | slot1->bytes[4] >> 4)) { xfull++; continue; } @@ -948,7 +937,7 @@ struct equi { } } } - // printf(" %d candidates ", nc); + printf(" %d candidates ", nc); } }; @@ -970,78 +959,53 @@ void *worker(void *vp) { thread_ctx *tp = (thread_ctx *)vp; equi *eq = tp->eq; - if (tp->id == 0) - printf("Digit 0"); - barrier(&eq->barry); + if (tp->id == 0) printf("Digit 0"); eq->digit0(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(0); barrier(&eq->barry); #if WN == 200 && WK == 9 && RESTBITS == 8 - if (tp->id == 0) printf("Digit 1"); - barrier(&eq->barry); eq->digit1(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(1); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 2"); - barrier(&eq->barry); eq->digit2(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(2); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 3"); - barrier(&eq->barry); eq->digit3(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(3); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 4"); - barrier(&eq->barry); eq->digit4(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(4); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 5"); - barrier(&eq->barry); eq->digit5(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(5); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 6"); - barrier(&eq->barry); eq->digit6(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(6); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 7"); - barrier(&eq->barry); eq->digit7(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(7); barrier(&eq->barry); - if (tp->id == 0) printf("Digit 8"); - barrier(&eq->barry); eq->digit8(tp->id); barrier(&eq->barry); if (tp->id == 0) eq->showbsizes(8); barrier(&eq->barry); #else 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) eq->showbsizes(r); barrier(&eq->barry); } #endif - if (tp->id == 0) - printf("Digit %d\n", WK); - barrier(&eq->barry); eq->digitK(tp->id); - barrier(&eq->barry); pthread_exit(NULL); return 0; }