Skip to content
Permalink
Browse files

CKB: support ckb-v0.25.0; support anonymous mining.

Full sync with dev branch dd7bc99 (2020.02.02-02).
  • Loading branch information
SwimmingTiger committed Feb 1, 2020
1 parent 5b86a71 commit b61461374616ab8e897f676058bc0bab1939e5bd
@@ -0,0 +1,71 @@
template <typename word_t>
class bitmap {
public:
word_t SIZE;
word_t BITMAP_WORDS;
#ifdef ATOMIC
typedef std::atomic<word_t> aword_t;
#else
typedef word_t aword_t;
#endif

typedef uint32_t u32;
typedef uint64_t u64;

aword_t *bits;
const static u32 BITS_PER_WORD = sizeof(word_t) * 8;

bitmap(word_t size) {
SIZE = size;
BITMAP_WORDS = SIZE / BITS_PER_WORD;
bits = new aword_t[BITMAP_WORDS];
assert(bits != 0);
}
~bitmap() {
freebits();
}
void freebits() {
delete[] bits;
bits = 0;
}
void clear() {
assert(bits);
memset((word_t *)bits, 0, BITMAP_WORDS*sizeof(word_t));
}
void prefetch(word_t u) const {
#ifdef PREFETCH
__builtin_prefetch((const void *)(&bits[u/BITS_PER_WORD]), /*READ=*/0, /*TEMPORAL=*/0);
#endif
}
void set(word_t u) {
word_t idx = u / BITS_PER_WORD;
word_t bit = (word_t)1 << (u % BITS_PER_WORD);
#ifdef ATOMIC
std::atomic_fetch_or_explicit(&bits[idx], bit, std::memory_order_relaxed);
#else
bits[idx] |= bit;
#endif
}
void reset(word_t u) {
word_t idx = u / BITS_PER_WORD;
word_t bit = (word_t)1 << (u % BITS_PER_WORD);
#ifdef ATOMIC
std::atomic_fetch_and_explicit(&bits[idx], ~bit, std::memory_order_relaxed);
#else
bits[idx] &= ~bit;
#endif
}
bool test(word_t u) const {
word_t idx = u / BITS_PER_WORD;
u32 bit = u % BITS_PER_WORD;
#ifdef ATOMIC
return (bits[idx].load(std::memory_order_relaxed) >> bit) & 1;
#else
return (bits[idx] >> bit) & 1;
#endif
}
word_t block(word_t n) const {
word_t idx = n / BITS_PER_WORD;
return bits[idx];
}
};
@@ -0,0 +1,80 @@
#include <new>

// compressor for cuckatoo nodes where edgetrimming
// has left at most 2^-compressbits nodes in each partition
typedef uint32_t u32;
typedef uint64_t u64;

template <typename word_t>
class compressor {
public:
u32 NODEBITS;
u32 COMPRESSBITS;
u32 SIZEBITS;
u32 SIZEBITS1;
word_t SIZE;
word_t MASK;
word_t MASK1;
word_t npairs;
const static word_t NIL = ~(word_t)0;
word_t *nodes;
bool sharedmem;

compressor(u32 nodebits, u32 compressbits, char *bytes) {
NODEBITS = nodebits;
COMPRESSBITS = compressbits;
SIZEBITS = NODEBITS-COMPRESSBITS;
SIZEBITS1 = SIZEBITS-1;
SIZE = (word_t)1 << SIZEBITS;
nodes = new (bytes) word_t[SIZE];
sharedmem = true;
MASK = SIZE-1;
MASK1 = MASK >> 1;
}

compressor(u32 nodebits, u32 compressbits) {
NODEBITS = nodebits;
COMPRESSBITS = compressbits;
SIZEBITS = NODEBITS-COMPRESSBITS;
SIZEBITS1 = SIZEBITS-1;
SIZE = (word_t)1 << SIZEBITS;
nodes = new word_t[SIZE];
sharedmem = false;
MASK = SIZE-1;
MASK1 = MASK >> 1;
}

~compressor() {
if (!sharedmem)
delete[] nodes;
}

uint64_t bytes() {
return sizeof(word_t[SIZE]);
}

void reset() {
memset(nodes, (char)NIL, sizeof(word_t[SIZE]));
npairs = 0;
}

word_t compress(word_t u) {
u32 parity = u & 1;
word_t ui = u >> COMPRESSBITS;
u >>= 1;
for (; ; ui = (ui+1) & MASK) {
word_t cu = nodes[ui];
if (cu == NIL) {
if (npairs >= SIZE/2) {
print_log("NODE OVERFLOW at %x\n", u << 1 | parity);
return parity;
}
nodes[ui] = u << SIZEBITS1 | npairs;
return (npairs++ << 1) | parity;
}
if ((cu & ~MASK1) == u << SIZEBITS1) {
return ((cu & MASK1) << 1) | parity;
}
}
}
};
@@ -10,12 +10,12 @@ static const uint64_t EDGE_BLOCK_MASK = EDGE_BLOCK_SIZE - 1;
static uint64_t sip_block(siphash_keys &keys, uint64_t edge, uint64_t *buf) {
siphash_state<> shs(keys);
uint64_t edge0 = edge & ~EDGE_BLOCK_MASK;
for (size_t i = 0; i < EDGE_BLOCK_SIZE; i++) {
for (uint64_t i = 0; i < EDGE_BLOCK_SIZE; i++) {
shs.hash24(edge0 + i);
buf[i] = shs.xor_lanes();
}
uint64_t last = buf[EDGE_BLOCK_MASK];
for (size_t i = 0; i < EDGE_BLOCK_MASK; i++)
for (uint64_t i = 0; i < EDGE_BLOCK_MASK; i++)
buf[i] ^= last;
return buf[edge & EDGE_BLOCK_MASK];
}
@@ -24,12 +24,12 @@ static uint64_t sip_block(siphash_keys &keys, uint64_t edge, uint64_t *buf) {
bool verify_cuckaroo(const std::vector<uint64_t> &edges, siphash_keys &keys, uint32_t edge_bits) {
uint64_t xor0 = 0, xor1 = 0;
uint64_t sips[EDGE_BLOCK_SIZE];
size_t proof_size = edges.size();
uint64_t proof_size = edges.size();
std::vector<uint64_t> uvs(2 * proof_size);
uint64_t edge_size = static_cast<uint64_t>(1) << edge_bits;
uint64_t edge_mask = edge_size - 1;

for (size_t n = 0; n < proof_size; n++) {
for (uint64_t n = 0; n < proof_size; n++) {
if (edges[n] > edge_mask)
return false;
if (n && edges[n] <= edges[n-1])
@@ -40,9 +40,9 @@ bool verify_cuckaroo(const std::vector<uint64_t> &edges, siphash_keys &keys, uin
}
if (xor0 | xor1) // optional check for obviously bad proofs
return false;
size_t n = 0, i = 0, j;
uint64_t n = 0, i = 0, j;
do { // follow cycle
for (size_t k = j = i; (k = (k + 2) % (2 * proof_size)) != i; ) {
for (uint64_t k = j = i; (k = (k + 2) % (2 * proof_size)) != i; ) {
if (uvs[k] == uvs[i]) { // find other edge endpoint identical to one at i
if (j != i) // already found one before
return false;
@@ -1,6 +1,10 @@
#include "cuckatoo.h"
#include "siphash.h"
#include "graph.hpp"

#include <thread>
#include <mutex>
#include <glog/logging.h>
// generate edge endpoint in cuck(at)oo graph without partition bit
static uint64_t sip_node(siphash_keys &keys, uint64_t edge, uint64_t uorv, uint64_t edge_mask) {
return keys.siphash24(2 * edge + uorv) & edge_mask;
@@ -9,13 +13,13 @@ static uint64_t sip_node(siphash_keys &keys, uint64_t edge, uint64_t uorv, uint6
// verify that edges are ascending and form a cycle in header-generated graph
bool verify_cuckatoo(const std::vector<uint64_t> &edges, siphash_keys &keys, uint32_t edge_bits) {
uint64_t xor0, xor1;
size_t proof_size = edges.size();
uint64_t proof_size = edges.size();
std::vector<uint64_t> uvs(2 * proof_size);
xor0 = xor1 = (proof_size / 2) & 1;
uint64_t edge_size = static_cast<uint64_t>(1) << edge_bits;
uint64_t edge_mask = edge_size - 1;

for (size_t n = 0; n < proof_size; n++) {
for (uint64_t n = 0; n < proof_size; n++) {
if (edges[n] > edge_mask)
return false;
if (n && edges[n] <= edges[n-1])
@@ -25,9 +29,9 @@ bool verify_cuckatoo(const std::vector<uint64_t> &edges, siphash_keys &keys, uin
}
if (xor0|xor1) // optional check for obviously bad proofs
return false;
size_t n = 0, i = 0, j;
uint64_t n = 0, i = 0, j;
do { // follow cycle
for (size_t k = j = i; (k = (k + 2) % (2 * proof_size)) != i; ) {
for (uint64_t k = j = i; (k = (k + 2) % (2 * proof_size)) != i; ) {
if (uvs[k]>>1 == uvs[i]>>1) { // find other edge endpoint matching one at i
if (j != i) // already found one before
return false;
@@ -40,4 +44,71 @@ bool verify_cuckatoo(const std::vector<uint64_t> &edges, siphash_keys &keys, uin
n++;
} while (i != 0); // must cycle back to start or we would have found branch
return n == proof_size;
}
}


static uint32_t sip_node_ae(siphash_keys &keys, uint32_t edge, uint32_t uorv, uint32_t edge_mask) {
uint32_t siphash = keys.siphash24ae(2 * edge + uorv) & edge_mask;
return (siphash << 1) | uorv;
}


bool verify_cuckatoo_ae(const std::vector<uint32_t> &edges, siphash_keys &keys, uint32_t edge_bits) {
uint32_t xor0, xor1;
uint32_t proof_size = edges.size();
std::vector<uint32_t> uvs(2 * proof_size);
xor0 = xor1 = 0; //(proof_size / 2) & 1;
uint32_t edge_size = static_cast<uint32_t>(1) << edge_bits;
uint32_t edge_mask = edge_size - 1;

for (uint32_t n = 0; n < proof_size; n++) {
if (edges[n] > edge_mask)
return false;
if (n && edges[n] <= edges[n-1])
return false;
xor0 ^= uvs[2*(proof_size-n-1) ] = sip_node_ae(keys, edges[n], 0, edge_mask);
xor1 ^= uvs[2*(proof_size-n-1)+1] = sip_node_ae(keys, edges[n], 1, edge_mask);
}
if (xor0|xor1) // optional check for obviously bad proofs
return false;
uint32_t n = 0, i = 0, j;
do { // follow cycle
for (uint32_t k = j = i; (k = (k + 2) % (2 * proof_size)) != i; ) {
if (uvs[k]>>1 == uvs[i]>>1) { // find other edge endpoint matching one at i
if (j != i) // already found one before
return false;
j = k;
}
}
if (j == i)
return false; // no matching endpoint
i = j^1;
n++;
} while (i != 0); // must cycle back to start or we would have found branch
return n == proof_size;
}

bool find_pow_ae(std::vector<uint32_t> &pow/*[output]*/, siphash_keys &sip_keys/*[input]*/, uint32_t easiness/*[input]*/) {
//uint32_t edge_bits = 29;//in ae ths EDGEBITS is 29
static std::mutex lock_for_find_pow;
std::lock_guard<std::mutex> lock(lock_for_find_pow);
uint32_t edge_size = static_cast<uint32_t>(1) << 29;
uint32_t edge_mask = edge_size - 1;
static graph<uint32_t> cg(edge_size, edge_size, 4);
cg.reset();
for (uint32_t nonce = 0; nonce < easiness; nonce++) {
uint32_t u = sip_node_ae(sip_keys, nonce, 0, edge_mask);
uint32_t v = sip_node_ae(sip_keys, nonce, 1, edge_mask);
cg.add_edge(u, v);
}
pow.resize(42);
for (uint32_t s=0; s < cg.nsols; s++) {
for(u32 j=0; j < 42; j++) {
pow[j] = (cg.sols[s][j]);
}
if (verify_cuckatoo_ae(pow, sip_keys, 29)) {
return true;
}
}
return false;
}
@@ -7,3 +7,7 @@
class siphash_keys;

bool verify_cuckatoo(const std::vector<uint64_t> &edges, siphash_keys &keys, uint32_t edge_bits);

bool verify_cuckatoo_ae(const std::vector<uint32_t> &edges, siphash_keys &keys, uint32_t edge_bits);

bool find_pow_ae(std::vector<uint32_t> &pow/*[output]*/, siphash_keys &sip_keys/*[input]*/, uint32_t easiness = 1/*[input]*/);

0 comments on commit b614613

Please sign in to comment.
You can’t perform that action at this time.