From 2acab1baf17c096ba9064f35b56d667e67a1f130 Mon Sep 17 00:00:00 2001 From: Warren Togami Date: Wed, 15 May 2013 17:13:59 -1000 Subject: [PATCH] Litecoin: Scrypt n=1024 Pow hash based upon Colin Percival's Tarnsnap (2009) Modified by Artforz, coblee, and pooler --- bitcoin-qt.pro | 2 + src/main.cpp | 65 ++------- src/main.h | 17 ++- src/makefile.linux-mingw | 1 + src/makefile.mingw | 1 + src/makefile.osx | 1 + src/makefile.unix | 1 + src/scrypt.cpp | 300 +++++++++++++++++++++++++++++++++++++++ src/scrypt.h | 17 +++ 9 files changed, 349 insertions(+), 56 deletions(-) create mode 100644 src/scrypt.cpp create mode 100644 src/scrypt.h diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 05de05184..6068f399e 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -204,6 +204,7 @@ HEADERS += src/qt/bitcoingui.h \ src/allocators.h \ src/ui_interface.h \ src/qt/rpcconsole.h \ + src/scrypt.h \ src/version.h \ src/netbase.h \ src/clientversion.h \ @@ -276,6 +277,7 @@ SOURCES += src/qt/bitcoin.cpp \ src/qt/notificator.cpp \ src/qt/paymentserver.cpp \ src/qt/rpcconsole.cpp \ + src/scrypt.cpp \ src/noui.cpp \ src/leveldb.cpp \ src/txdb.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 226d32295..4bed65a76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2093,7 +2093,7 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk } // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) + if (fCheckPOW && !CheckProofOfWork(GetPoWHash(), nBits)) return state.DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp @@ -4083,41 +4083,6 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit) ((uint32_t*)pstate)[i] = ctx.h[i]; } -// -// ScanHash scans nonces looking for a hash with at least some zero bits. -// It operates on big endian data. Caller does the byte reversing. -// All input buffers are 16-byte aligned. nNonce is usually preserved -// between calls, but periodically or if nNonce is 0xffff0000 or above, -// the block is rebuilt and nNonce starts over at zero. -// -unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) -{ - unsigned int& nNonce = *(unsigned int*)(pdata + 12); - for (;;) - { - // Crypto++ SHA256 - // Hash pdata using pmidstate as the starting state into - // pre-formatted buffer phash1, then hash phash1 into phash - nNonce++; - SHA256Transform(phash1, pdata, pmidstate); - SHA256Transform(phash, phash1, pSHA256InitState); - - // Return the nonce if the hash has at least some zero bits, - // caller will check if it has enough to reach the target - if (((unsigned short*)phash)[14] == 0) - return nNonce; - - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xffff) == 0) - { - nHashesDone = 0xffff+1; - return (unsigned int) -1; - } - if ((nNonce & 0xfff) == 0) - boost::this_thread::interruption_point(); - } -} - // Some explaining would be appreciated class COrphan { @@ -4483,7 +4448,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { - uint256 hash = pblock->GetHash(); + uint256 hash = pblock->GetPoWHash(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); if (hash > hashTarget) @@ -4567,34 +4532,28 @@ void static BitcoinMiner(CWallet *pwallet) // int64 nStart = GetTime(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - uint256 hashbuf[2]; - uint256& hash = *alignup<16>(hashbuf); loop { unsigned int nHashesDone = 0; - unsigned int nNonceFound; - // Crypto++ SHA256 - nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1, - (char*)&hash, nHashesDone); - - // Check if something found - if (nNonceFound != (unsigned int) -1) + uint256 thash; + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + loop { - for (unsigned int i = 0; i < sizeof(hash)/4; i++) - ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]); + scrypt_1024_1_1_256_sp(BEGIN(pblock->nVersion), BEGIN(thash), scratchpad); - if (hash <= hashTarget) + if (thash <= hashTarget) { // Found a solution - pblock->nNonce = ByteReverse(nNonceFound); - assert(hash == pblock->GetHash()); - SetThreadPriority(THREAD_PRIORITY_NORMAL); CheckWork(pblock, *pwalletMain, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); break; } + pblock->nNonce += 1; + nHashesDone += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; } // Meter hashes/sec @@ -4630,7 +4589,7 @@ void static BitcoinMiner(CWallet *pwallet) boost::this_thread::interruption_point(); if (vNodes.empty()) break; - if (nBlockNonce >= 0xffff0000) + if (pblock->nNonce >= 0xffff0000) break; if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; diff --git a/src/main.h b/src/main.h index 8e71e66cc..42578a684 100644 --- a/src/main.h +++ b/src/main.h @@ -9,6 +9,7 @@ #include "sync.h" #include "net.h" #include "script.h" +#include "scrypt.h" #include @@ -1344,6 +1345,13 @@ public: vMerkleTree.clear(); } + uint256 GetPoWHash() const + { + uint256 thash; + scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash)); + return thash; + } + CBlockHeader GetBlockHeader() const { CBlockHeader block; @@ -1456,7 +1464,7 @@ public: } // Check the header - if (!CheckProofOfWork(GetHash(), nBits)) + if (!CheckProofOfWork(GetPoWHash(), nBits)) return error("CBlock::ReadFromDisk() : errors in block header"); return true; @@ -1466,8 +1474,9 @@ public: void print() const { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + printf("CBlock(hash=%s, PoW=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", GetHash().ToString().c_str(), + GetPoWHash().ToString().c_str(), nVersion, hashPrevBlock.ToString().c_str(), hashMerkleRoot.ToString().c_str(), @@ -1738,7 +1747,9 @@ public: bool CheckIndex() const { - return CheckProofOfWork(GetBlockHash(), nBits); + /** Scrypt is used for block proof-of-work, but for purposes of performance the index internally uses sha256. + * This check was considered unneccessary given the other safeguards like the genesis and checkpoints. */ + return true; // return CheckProofOfWork(GetBlockHash(), nBits); } enum { nMedianTimeSpan=11 }; diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 7719cd263..401b367f1 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -83,6 +83,7 @@ OBJS= \ obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ + obj/scrypt.o \ obj/sync.o \ obj/util.o \ obj/wallet.o \ diff --git a/src/makefile.mingw b/src/makefile.mingw index 8b5a5dccd..ef2ad9537 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -91,6 +91,7 @@ OBJS= \ obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ + obj/scrypt.o \ obj/sync.o \ obj/util.o \ obj/wallet.o \ diff --git a/src/makefile.osx b/src/makefile.osx index 50279fdb0..2323de66c 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -94,6 +94,7 @@ OBJS= \ obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ + obj/scrypt.o \ obj/sync.o \ obj/util.o \ obj/wallet.o \ diff --git a/src/makefile.unix b/src/makefile.unix index 811023564..e404b2824 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -133,6 +133,7 @@ OBJS= \ obj/rpcblockchain.o \ obj/rpcrawtransaction.o \ obj/script.o \ + obj/scrypt.o \ obj/sync.o \ obj/util.o \ obj/wallet.o \ diff --git a/src/scrypt.cpp b/src/scrypt.cpp new file mode 100644 index 000000000..a7db3e702 --- /dev/null +++ b/src/scrypt.cpp @@ -0,0 +1,300 @@ +/* + * Copyright 2009 Colin Percival, 2011 ArtForz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include "scrypt.h" +#include +#include +#include +#include + +static inline uint32_t be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void be32enc(void *pp, uint32_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline uint32_t le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void le32enc(void *pp, uint32_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +/* Initialize an HMAC-SHA256 operation with the given key. */ +static void +HMAC_SHA256_Init(HMAC_SHA256_CTX *ctx, const unsigned char *_K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char *K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Update(HMAC_SHA256_CTX *ctx, const void *in, size_t len) +{ + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX *ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +static void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} + + +#define ROTL(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) + +static inline void xor_salsa8(uint32_t B[16], const uint32_t Bx[16]) +{ + uint32_t x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15; + int i; + + x00 = (B[ 0] ^= Bx[ 0]); + x01 = (B[ 1] ^= Bx[ 1]); + x02 = (B[ 2] ^= Bx[ 2]); + x03 = (B[ 3] ^= Bx[ 3]); + x04 = (B[ 4] ^= Bx[ 4]); + x05 = (B[ 5] ^= Bx[ 5]); + x06 = (B[ 6] ^= Bx[ 6]); + x07 = (B[ 7] ^= Bx[ 7]); + x08 = (B[ 8] ^= Bx[ 8]); + x09 = (B[ 9] ^= Bx[ 9]); + x10 = (B[10] ^= Bx[10]); + x11 = (B[11] ^= Bx[11]); + x12 = (B[12] ^= Bx[12]); + x13 = (B[13] ^= Bx[13]); + x14 = (B[14] ^= Bx[14]); + x15 = (B[15] ^= Bx[15]); + for (i = 0; i < 8; i += 2) { + /* Operate on columns. */ + x04 ^= ROTL(x00 + x12, 7); x09 ^= ROTL(x05 + x01, 7); + x14 ^= ROTL(x10 + x06, 7); x03 ^= ROTL(x15 + x11, 7); + + x08 ^= ROTL(x04 + x00, 9); x13 ^= ROTL(x09 + x05, 9); + x02 ^= ROTL(x14 + x10, 9); x07 ^= ROTL(x03 + x15, 9); + + x12 ^= ROTL(x08 + x04, 13); x01 ^= ROTL(x13 + x09, 13); + x06 ^= ROTL(x02 + x14, 13); x11 ^= ROTL(x07 + x03, 13); + + x00 ^= ROTL(x12 + x08, 18); x05 ^= ROTL(x01 + x13, 18); + x10 ^= ROTL(x06 + x02, 18); x15 ^= ROTL(x11 + x07, 18); + + /* Operate on rows. */ + x01 ^= ROTL(x00 + x03, 7); x06 ^= ROTL(x05 + x04, 7); + x11 ^= ROTL(x10 + x09, 7); x12 ^= ROTL(x15 + x14, 7); + + x02 ^= ROTL(x01 + x00, 9); x07 ^= ROTL(x06 + x05, 9); + x08 ^= ROTL(x11 + x10, 9); x13 ^= ROTL(x12 + x15, 9); + + x03 ^= ROTL(x02 + x01, 13); x04 ^= ROTL(x07 + x06, 13); + x09 ^= ROTL(x08 + x11, 13); x14 ^= ROTL(x13 + x12, 13); + + x00 ^= ROTL(x03 + x02, 18); x05 ^= ROTL(x04 + x07, 18); + x10 ^= ROTL(x09 + x08, 18); x15 ^= ROTL(x14 + x13, 18); + } + B[ 0] += x00; + B[ 1] += x01; + B[ 2] += x02; + B[ 3] += x03; + B[ 4] += x04; + B[ 5] += x05; + B[ 6] += x06; + B[ 7] += x07; + B[ 8] += x08; + B[ 9] += x09; + B[10] += x10; + B[11] += x11; + B[12] += x12; + B[13] += x13; + B[14] += x14; + B[15] += x15; +} + +void scrypt_1024_1_1_256_sp(const char *input, char *output, char *scratchpad) +{ + uint8_t B[128]; + uint32_t X[32]; + uint32_t *V; + uint32_t i, j, k; + + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128); + + for (k = 0; k < 32; k++) + X[k] = le32dec(&B[4 * k]); + + for (i = 0; i < 1024; i++) { + memcpy(&V[i * 32], X, 128); + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + for (i = 0; i < 1024; i++) { + j = 32 * (X[16] & 1023); + for (k = 0; k < 32; k++) + X[k] ^= V[j + k]; + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + + for (k = 0; k < 32; k++) + le32enc(&B[4 * k], X[k]); + + PBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32); +} + +void scrypt_1024_1_1_256(const char *input, char *output) +{ + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + scrypt_1024_1_1_256_sp(input, output, scratchpad); +} diff --git a/src/scrypt.h b/src/scrypt.h new file mode 100644 index 000000000..4f9c2e337 --- /dev/null +++ b/src/scrypt.h @@ -0,0 +1,17 @@ +#ifndef SCRYPT_H +#define SCRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCRYPT_SCRATCHPAD_SIZE (131072 + 63) + +void scrypt_1024_1_1_256_sp(const char *input, char *output, char *scratchpad); +void scrypt_1024_1_1_256(const char *input, char *output); + +#ifdef __cplusplus +} +#endif + +#endif