diff --git a/cryptopp/sha256.cpp b/cryptopp/sha256.cpp new file mode 100644 index 0000000..15f8be1 --- /dev/null +++ b/cryptopp/sha256.cpp @@ -0,0 +1,443 @@ +#include +#include + +#include +#include +#include + +#define NPAR 32 + +static const unsigned int sha256_consts[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, /* 0 */ + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, /* 8 */ + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, /* 16 */ + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, /* 24 */ + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, /* 32 */ + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, /* 40 */ + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, /* 48 */ + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, /* 56 */ + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + +static inline __m128i Ch(const __m128i b, const __m128i c, const __m128i d) { + return (b & c) ^ (~b & d); +} + +static inline __m128i Maj(const __m128i b, const __m128i c, const __m128i d) { + return (b & c) ^ (b & d) ^ (c & d); +} + +static inline __m128i ROTR(__m128i x, const int n) { + return _mm_srli_epi32(x, n) | _mm_slli_epi32(x, 32 - n); +} + +static inline __m128i SHR(__m128i x, const int n) { + return _mm_srli_epi32(x, n); +} + +/* SHA256 Functions */ +#define BIGSIGMA0_256(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22)) +#define BIGSIGMA1_256(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25)) +#define SIGMA0_256(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ SHR((x), 3)) +#define SIGMA1_256(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ SHR((x), 10)) + +static inline __m128i load_epi32(const unsigned int x0, const unsigned int x1, const unsigned int x2, const unsigned int x3) { + return _mm_set_epi32(x0, x1, x2, x3); +} + +static inline unsigned int store32(const __m128i x, int i) { + union { unsigned int ret[4]; __m128i x; } box; + box.x = x; + return box.ret[i]; +} + +static inline void store_epi32(const __m128i x, unsigned int *x0, unsigned int *x1, unsigned int *x2, unsigned int *x3) { + union { unsigned int ret[4]; __m128i x; } box; + box.x = x; + *x0 = box.ret[3]; *x1 = box.ret[2]; *x2 = box.ret[1]; *x3 = box.ret[0]; +} + +static inline __m128i SHA256_CONST(const int i) { + return _mm_set1_epi32(sha256_consts[i]); +} + +#define add4(x0, x1, x2, x3) _mm_add_epi32(_mm_add_epi32(_mm_add_epi32(x0, x1), x2), x3) +#define add5(x0, x1, x2, x3, x4) _mm_add_epi32(add4(x0, x1, x2, x3), x4) + +#define SHA256ROUND(a, b, c, d, e, f, g, h, i, w) \ + T1 = add5(h, BIGSIGMA1_256(e), Ch(e, f, g), SHA256_CONST(i), w); \ +d = _mm_add_epi32(d, T1); \ +T2 = _mm_add_epi32(BIGSIGMA0_256(a), Maj(a, b, c)); \ +h = _mm_add_epi32(T1, T2); + +#define SHA256ROUND_lastd(a, b, c, d, e, f, g, h, i, w) \ + T1 = add5(h, BIGSIGMA1_256(e), Ch(e, f, g), SHA256_CONST(i), w); \ +d = _mm_add_epi32(d, T1); +//T2 = _mm_add_epi32(BIGSIGMA0_256(a), Maj(a, b, c)); +//h = _mm_add_epi32(T1, T2); + +#define SHA256ROUND_last(a, b, c, d, e, f, g, h, i, w) \ + T1 = add5(h, BIGSIGMA1_256(e), Ch(e, f, g), SHA256_CONST(i), w); \ +T2 = _mm_add_epi32(BIGSIGMA0_256(a), Maj(a, b, c)); \ +h = _mm_add_epi32(T1, T2); + +static inline unsigned int swap(unsigned int value) { + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +} + +static inline unsigned int SWAP32(const void *addr) { + unsigned int value = (*((unsigned int *)(addr))); + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +} + +static inline void dumpreg(__m128i x, char *msg) { + union { unsigned int ret[4]; __m128i x; } box; + box.x = x ; + printf("%s %08x %08x %08x %08x\n", msg, box.ret[0], box.ret[1], box.ret[2], box.ret[3]); +} + +#if 1 +#define dumpstate(i) printf("%s: %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", \ + __func__, store32(w0, i), store32(a, i), store32(b, i), store32(c, i), store32(d, i), store32(e, i), store32(f, i), store32(g, i), store32(h, i)); +#else +#define dumpstate() +#endif +void Double_BlockSHA256(const void* pin, void* pad, const void *pre, unsigned int thash[8][NPAR], const void *init) +{ + unsigned int* In = (unsigned int*)pin; + unsigned int* Pad = (unsigned int*)pad; + unsigned int* hPre = (unsigned int*)pre; + unsigned int* hInit = (unsigned int*)init; + unsigned int i, j, k; + + /* vectors used in calculation */ + __m128i w0, w1, w2, w3, w4, w5, w6, w7; + __m128i w8, w9, w10, w11, w12, w13, w14, w15; + __m128i T1, T2; + __m128i a, b, c, d, e, f, g, h; + + /* nonce offset for vector */ + __m128i offset = load_epi32(0x00000003, 0x00000002, 0x00000001, 0x00000000); + + + for(k = 0; knBits).getuint256(); uint256 hashbuf[2]; uint256& hash = *alignup<16>(hashbuf); + + // Cache for NPAR hashes + unsigned int thash[8][NPAR]; + + unsigned int j; loop { - SHA256Transform(&tmp.hash1, (char*)&tmp.block + 64, &midstate); - SHA256Transform(&hash, &tmp.hash1, pSHA256InitState); + Double_BlockSHA256((char*)&tmp.block + 64, &tmp.hash1, &midstate, thash, pSHA256InitState); - if (((unsigned short*)&hash)[14] == 0) + for(j = 0; jnNonce = ByteReverse(tmp.block.nNonce + j); + //hash = pblock->GetHash(); + + pblock->nNonce = ByteReverse(tmp.block.nNonce + j); + assert(hash == pblock->GetHash()); + + //// debug print + printf("BitcoinMiner:\n"); + printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); + printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); + + SetThreadPriority(THREAD_PRIORITY_NORMAL); + CRITICAL_BLOCK(cs_main) { - pblock->nNonce = ByteReverse(tmp.block.nNonce); - assert(hash == pblock->GetHash()); - - //// debug print - printf("BitcoinMiner:\n"); - printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); - pblock->print(); - printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); - printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); - - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CRITICAL_BLOCK(cs_main) - { - if (pindexPrev == pindexBest) - { - // Save key - if (!AddKey(key)) - return; - key.MakeNewKey(); - - // Track how many getdata requests this block gets - CRITICAL_BLOCK(cs_mapRequestCount) - mapRequestCount[pblock->GetHash()] = 0; - - // Process this block the same as if we had received it from another node - if (!ProcessBlock(NULL, pblock.release())) - printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n"); - } - } - SetThreadPriority(THREAD_PRIORITY_LOWEST); - - Sleep(500); - break; + if (pindexPrev == pindexBest) + { + // Save key + if (!AddKey(key)) + return; + key.MakeNewKey(); + + // Track how many getdata requests this block gets + CRITICAL_BLOCK(cs_mapRequestCount) + mapRequestCount[pblock->GetHash()] = 0; + + // Process this block the same as if we had received it from another node + if (!ProcessBlock(NULL, pblock.release())) + printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n"); + + } } - } + SetThreadPriority(THREAD_PRIORITY_LOWEST); - // Update nTime every few seconds - const unsigned int nMask = 0xffff; - if ((++tmp.block.nNonce & nMask) == 0) + Sleep(500); + break; + } + } + } + + // Update nonce + tmp.block.nNonce += NPAR; + + // Update nTime every few seconds + const unsigned int nMask = 0xffff; + if ((tmp.block.nNonce & nMask) == 0) + { + // Meter hashes/sec + static int64 nTimerStart; + static int nHashCounter; + if (nTimerStart == 0) + nTimerStart = GetTimeMillis(); + else + nHashCounter++; + if (GetTimeMillis() - nTimerStart > 4000) { - // Meter hashes/sec - static int64 nTimerStart; - static int nHashCounter; - if (nTimerStart == 0) - nTimerStart = GetTimeMillis(); - else - nHashCounter++; + static CCriticalSection cs; + CRITICAL_BLOCK(cs) + { if (GetTimeMillis() - nTimerStart > 4000) { - static CCriticalSection cs; - CRITICAL_BLOCK(cs) - { - if (GetTimeMillis() - nTimerStart > 4000) - { - double dHashesPerSec = 1000.0 * (nMask+1) * nHashCounter / (GetTimeMillis() - nTimerStart); - nTimerStart = GetTimeMillis(); - nHashCounter = 0; - string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0); - UIThreadCall(bind(CalledSetStatusBar, strStatus, 0)); - static int64 nLogTime; - if (GetTime() - nLogTime > 30 * 60) - { - nLogTime = GetTime(); - printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); - printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0); - } - } - } + double dHashesPerSec = 1000.0 * (nMask+1) * nHashCounter / (GetTimeMillis() - nTimerStart); + nTimerStart = GetTimeMillis(); + nHashCounter = 0; + string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0); + UIThreadCall(bind(CalledSetStatusBar, strStatus, 0)); + static int64 nLogTime; + if (GetTime() - nLogTime > 30 * 60) + { + nLogTime = GetTime(); + printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); + printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0); + } } - - // Check for stop or if block needs to be rebuilt - if (fShutdown) - return; - if (!fGenerateBitcoins) - return; - if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors) - return; - if (vNodes.empty()) - break; - if (tmp.block.nNonce == 0) - break; - if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != pindexBest) - break; - - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - tmp.block.nTime = ByteReverse(pblock->nTime); + } } + + // Check for stop or if block needs to be rebuilt + if (fShutdown) + return; + if (!fGenerateBitcoins) + return; + if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors) + return; + if (vNodes.empty()) + break; + if (tmp.block.nNonce == 0) + break; + if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != pindexBest) + break; + + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + tmp.block.nTime = ByteReverse(pblock->nTime); + } } } } diff --git a/makefile.unix b/makefile.unix index 597a0ea..8fb0aa6 100755 --- a/makefile.unix +++ b/makefile.unix @@ -45,7 +45,8 @@ OBJS= \ obj/rpc.o \ obj/init.o \ cryptopp/obj/sha.o \ - cryptopp/obj/cpu.o + cryptopp/obj/cpu.o \ + cryptopp/obj/sha256.o all: bitcoin @@ -58,18 +59,20 @@ obj/%.o: %.cpp $(HEADERS) headers.h.gch g++ -c $(CFLAGS) -DGUI -o $@ $< cryptopp/obj/%.o: cryptopp/%.cpp - g++ -c $(CFLAGS) -O3 -DCRYPTOPP_DISABLE_SSE2 -o $@ $< + g++ -c $(CFLAGS) -frename-registers -funroll-all-loops -fomit-frame-pointer -march=native -msse2 -msse3 -ffast-math -O3 -o $@ $< bitcoin: $(OBJS) obj/ui.o obj/uibase.o g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS) - obj/nogui/%.o: %.cpp $(HEADERS) g++ -c $(CFLAGS) -o $@ $< bitcoind: $(OBJS:obj/%=obj/nogui/%) g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) +test: cryptopp/obj/sha.o cryptopp/obj/sha256.o test.cpp + g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS) + clean: -rm -f obj/*.o diff --git a/test.cpp b/test.cpp new file mode 100755 index 0000000..7cab332 --- /dev/null +++ b/test.cpp @@ -0,0 +1,237 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace boost; +#include "cryptopp/sha.h" +#include "strlcpy.h" +#include "serialize.h" +#include "uint256.h" +#include "bignum.h" + +#undef printf + template +T* alignup(T* p) +{ + union + { + T* ptr; + size_t n; + } u; + u.ptr = p; + u.n = (u.n + (nBytes-1)) & ~(nBytes-1); + return u.ptr; +} + +int FormatHashBlocks(void* pbuffer, unsigned int len) +{ + unsigned char* pdata = (unsigned char*)pbuffer; + unsigned int blocks = 1 + ((len + 8) / 64); + unsigned char* pend = pdata + 64 * blocks; + memset(pdata + len, 0, 64 * blocks - len); + pdata[len] = 0x80; + unsigned int bits = len * 8; + pend[-1] = (bits >> 0) & 0xff; + pend[-2] = (bits >> 8) & 0xff; + pend[-3] = (bits >> 16) & 0xff; + pend[-4] = (bits >> 24) & 0xff; + return blocks; +} + +using CryptoPP::ByteReverse; +static int detectlittleendian = 1; + +#define NPAR 32 + +extern void Double_BlockSHA256(const void* pin, void* pout, const void *pinit, unsigned int hash[8][NPAR], const void *init2); + +using CryptoPP::ByteReverse; + +static const unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +inline void SHA256Transform(void* pstate, void* pinput, const void* pinit) +{ + memcpy(pstate, pinit, 32); + CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput); +} + +void BitcoinTester(char *filename) +{ + printf("SHA256 test started\n"); + + struct tmpworkspace + { + struct unnamed2 + { + int nVersion; + uint256 hashPrevBlock; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + } + block; + unsigned char pchPadding0[64]; + uint256 hash1; + unsigned char pchPadding1[64]; + }; + char tmpbuf[sizeof(tmpworkspace)+16]; + tmpworkspace& tmp = *(tmpworkspace*)alignup<16>(tmpbuf); + + + char line[180]; + ifstream fin(filename); + char *p; + unsigned long int totalhashes= 0; + unsigned long int found = 0; + clock_t start, end; + unsigned long int cpu_time_used; + unsigned int tnonce; + start = clock(); + + while( fin.getline(line, 180)) + { + string in(line); + //printf("%s\n", in.c_str()); + tmp.block.nVersion = strtol(in.substr(0,8).c_str(), &p, 16); + tmp.block.hashPrevBlock.SetHex(in.substr(8,64)); + tmp.block.hashMerkleRoot.SetHex(in.substr(64+8,64)); + tmp.block.nTime = strtol(in.substr(128+8,8).c_str(), &p, 16); + tmp.block.nBits = strtol(in.substr(128+16,8).c_str(), &p, 16); + tnonce = strtol(in.substr(128+24,8).c_str(), &p, 16); + tmp.block.nNonce = tnonce; + + unsigned int nBlocks0 = FormatHashBlocks(&tmp.block, sizeof(tmp.block)); + unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); + + // Byte swap all the input buffer + for (int i = 0; i < sizeof(tmp)/4; i++) + ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]); + + // Precalc the first half of the first hash, which stays constant + uint256 midstatebuf[2]; + uint256& midstate = *alignup<16>(midstatebuf); + SHA256Transform(&midstate, &tmp.block, pSHA256InitState); + + + uint256 hashTarget = CBigNum().SetCompact(ByteReverse(tmp.block.nBits)).getuint256(); + // printf("target %s\n", hashTarget.GetHex().c_str()); + uint256 hash; + uint256 hashbuf[2]; + uint256& refhash = *alignup<16>(hashbuf); + + unsigned int thash[8][NPAR]; + int done = 0; + unsigned int i, j; + + /* reference */ + SHA256Transform(&tmp.hash1, (char*)&tmp.block + 64, &midstate); + SHA256Transform(&refhash, &tmp.hash1, pSHA256InitState); + for (int i = 0; i < sizeof(refhash)/4; i++) + ((unsigned int*)&refhash)[i] = ByteReverse(((unsigned int*)&refhash)[i]); + + //printf("reference nonce %08x:\n%s\n\n", tnonce, refhash.GetHex().c_str()); + + tmp.block.nNonce = ByteReverse(tnonce) & 0xfffff000; + + + for(;;) + { + + Double_BlockSHA256((char*)&tmp.block + 64, &tmp.hash1, &midstate, thash, pSHA256InitState); + + for(i = 0; i