Files
cpuminer-opt-gpu/algo/scryptjane/scrypt-jane.c
Jay D Dee 86b889e1b0 v3.9.9.1
2019-10-24 14:11:26 -04:00

265 lines
6.8 KiB
C

#include <stdlib.h>
#include <string.h>
#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<b ? b : a)
#endif
#define scrypt_maxN 30 /* (1 << (30 + 1)) = ~2 billion */
#if (SCRYPT_BLOCK_BYTES == 64)
#define scrypt_r_32kb 8 /* (1 << 8) = 256 * 2 blocks in a chunk * 64 bytes = Max of 32kb in a chunk */
#elif (SCRYPT_BLOCK_BYTES == 128)
#define scrypt_r_32kb 7 /* (1 << 7) = 128 * 2 blocks in a chunk * 128 bytes = Max of 32kb in a chunk */
#elif (SCRYPT_BLOCK_BYTES == 256)
#define scrypt_r_32kb 6 /* (1 << 6) = 64 * 2 blocks in a chunk * 256 bytes = Max of 32kb in a chunk */
#elif (SCRYPT_BLOCK_BYTES == 512)
#define scrypt_r_32kb 5 /* (1 << 5) = 32 * 2 blocks in a chunk * 512 bytes = Max of 32kb in a chunk */
#endif
#define scrypt_maxr scrypt_r_32kb /* 32kb */
#define scrypt_maxp 25 /* (1 << 25) = ~33 million */
uint64_t sj_N;
typedef struct scrypt_aligned_alloc_t {
uint8_t *mem, *ptr;
} scrypt_aligned_alloc;
static int
scrypt_alloc(uint64_t size, scrypt_aligned_alloc *aa) {
static const size_t max_alloc = (size_t)-1;
size += (SCRYPT_BLOCK_BYTES - 1);
if (size > 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 (N<minNfactor) return minNfactor;
if (N>maxNfactor) 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;
}