#include #include #include "inttypes.h" #include "algo-gate-api.h" /* Hard-coded scrypt parameteres r and p - mikaelh */ #define SCRYPT_R 1 #define SCRYPT_P 1 /* Only the instrinsics versions are optimized for hard-coded values - mikaelh */ #define CPU_X86_FORCE_INTRINSICS #undef SCRYPT_KECCAK512 #undef SCRYPT_CHACHA #undef SCRYPT_CHOOSE_COMPILETIME #define SCRYPT_KECCAK512 #define SCRYPT_CHACHA #define SCRYPT_CHOOSE_COMPILETIME //#include "scrypt-jane.h" #include "../scryptjane/scrypt-jane-portable.h" #include "../scryptjane/scrypt-jane-hash.h" #include "../scryptjane/scrypt-jane-romix.h" #include "../scryptjane/scrypt-jane-test-vectors.h" #ifndef min #define min(a,b) (a>b ? b : a) #endif #ifndef max #define max(a,b) (a max_alloc) return 0; // scrypt_fatal_error("scrypt: not enough address space on this CPU to allocate required memory"); aa->mem = (uint8_t *)malloc((size_t)size); aa->ptr = (uint8_t *)(((size_t)aa->mem + (SCRYPT_BLOCK_BYTES - 1)) & ~(SCRYPT_BLOCK_BYTES - 1)); if (!aa->mem) return 0; // scrypt_fatal_error("scrypt: out of memory"); return 1; } static void scrypt_free(scrypt_aligned_alloc *aa) { free(aa->mem); } void scrypt_N_1_1(const uint8_t *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t N, uint8_t *out, size_t bytes, uint8_t *X, uint8_t *Y, uint8_t *V) { uint32_t chunk_bytes, i; const uint32_t r = SCRYPT_R; const uint32_t p = SCRYPT_P; #if !defined(SCRYPT_CHOOSE_COMPILETIME) scrypt_ROMixfn scrypt_ROMix = scrypt_getROMix(); #endif chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; /* 1: X = PBKDF2(password, salt) */ scrypt_pbkdf2_1(password, password_len, salt, salt_len, X, chunk_bytes * p); /* 2: X = ROMix(X) */ for (i = 0; i < p; i++) scrypt_ROMix_1((scrypt_mix_word_t *)(X + (chunk_bytes * i)), (scrypt_mix_word_t *)Y, (scrypt_mix_word_t *)V, N); /* 3: Out = PBKDF2(password, X) */ scrypt_pbkdf2_1(password, password_len, X, chunk_bytes * p, out, bytes); #ifdef SCRYPT_PREVENT_STATE_LEAK /* This is an unnecessary security feature - mikaelh */ scrypt_ensure_zero(Y, (p + 1) * chunk_bytes); #endif } // increasing Nfactor gradually const unsigned char minNfactor = 4; const unsigned char maxNfactor = 30; unsigned char GetNfactor(unsigned int nTimestamp, unsigned int ntime) { int l = 0; unsigned long int s; int n; unsigned char N; if (nTimestamp <= ntime) return 4; s = nTimestamp - ntime; while ((s >> 1) > 3) { l += 1; s >>= 1; } s &= 3; n = (l * 170 + s * 25 - 2320) / 100; if (n < 0) n = 0; if (n > 255) { n = 255; // printf("GetNfactor(%d) - something wrong(n == %d)\n", nTimestamp, n); } N = (unsigned char)n; //printf("GetNfactor: %d -> %d %d : %d / %d\n", nTimestamp - nChainStartTime, l, s, n, min(max(N, minNfactor), maxNfactor)); if (NmaxNfactor) return maxNfactor; return N; } int scanhash_scryptjane( struct work *work, uint32_t max_nonce, uint64_t *hashes_done, struct thr_info *mythr ) { scrypt_aligned_alloc YX, V; uint8_t *X, *Y; // uint32_t N, chunk_bytes; uint32_t chunk_bytes; const uint32_t r = SCRYPT_R; const uint32_t p = SCRYPT_P; uint32_t *pdata = work->data; uint32_t *ptarget = work->target; uint32_t _ALIGN(64) endiandata[20]; const uint32_t first_nonce = pdata[19]; uint32_t nonce = first_nonce; int thr_id = mythr->id; // thr_id arg is deprecated if (opt_benchmark) ptarget[7] = 0x00ff; for (int k = 0; k < 19; k++) be32enc(&endiandata[k], pdata[k]); //Nfactor = GetNfactor(data[17], ntime); //if (Nfactor > scrypt_maxN) { // return 1; // //scrypt_fatal_error("scrypt: N out of range"); //} // opt_scrypt_n default is 1024 which makes no sense in this context // and results in N = 2, but it seems to work on Nicehash scryptjanenf16 // (leocoin). Need to test with proper NF 16 for functionality and performance. // Also test yacoin (NF 18). // N = (1 << ( opt_scrypt_n + 1)); chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; if (!scrypt_alloc( sj_N * chunk_bytes, &V ) ) return 1; if (!scrypt_alloc((p + 1) * chunk_bytes, &YX)) { scrypt_free(&V); return 1; } Y = YX.ptr; X = Y + chunk_bytes; do { const uint32_t Htarg = ptarget[7]; uint32_t hash[8]; be32enc(&endiandata[19], nonce); scrypt_N_1_1((unsigned char *)endiandata, 80, (unsigned char *)endiandata, 80, sj_N, (unsigned char *)hash, 32, X, Y, V.ptr); if (hash[7] <= Htarg && fulltest(hash, ptarget)) { pdata[19] = nonce; *hashes_done = pdata[19] - first_nonce; scrypt_free(&V); scrypt_free(&YX); return 1; } nonce++; } while (nonce < max_nonce && !work_restart[thr_id].restart); pdata[19] = nonce; *hashes_done = pdata[19] - first_nonce + 1; scrypt_free(&V); scrypt_free(&YX); return 0; } /* simple cpu test (util.c) */ void scryptjanehash(void *output, const void *input ) { scrypt_aligned_alloc YX, V; uint8_t *X, *Y; uint32_t chunk_bytes; const uint32_t r = SCRYPT_R; const uint32_t p = SCRYPT_P; memset(output, 0, 32); chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; if (!scrypt_alloc( sj_N * chunk_bytes, &V ) ) return; if (!scrypt_alloc((p + 1) * chunk_bytes, &YX)) { scrypt_free(&V); return; } Y = YX.ptr; X = Y + chunk_bytes; scrypt_N_1_1((unsigned char*)input, 80, (unsigned char*)input, 80, sj_N, (unsigned char*)output, 32, X, Y, V.ptr); scrypt_free(&V); scrypt_free(&YX); } bool register_scryptjane_algo( algo_gate_t* gate ) { gate->scanhash = (void*)&scanhash_scryptjane; gate->hash = (void*)&scryptjanehash; opt_target_factor = 65536.0; // figure out if arg in N or Nfactor if ( !opt_param_n ) { applog( LOG_ERR, "The N factor must be specified in the form algo:nf"); return false; } else if ( opt_param_n < 32 ) { // arg is Nfactor, calculate N sj_N = 1 << ( opt_param_n + 1 ); } else { // arg is N sj_N = opt_param_n; } return true; }