You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1290 lines
35 KiB

/******************************************************************************
* Copyright © 2014-2017 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include "../iguana/iguana777.h"
int32_t smallprimes[168] =
{
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997
};
bits256 bits256_doublesha256(char *hashstr,uint8_t *data,int32_t datalen)
{
bits256 hash,hash2; int32_t i;
vcalc_sha256(0,hash.bytes,data,datalen);
vcalc_sha256(0,hash2.bytes,hash.bytes,sizeof(hash));
for (i=0; i<sizeof(hash); i++)
hash.bytes[i] = hash2.bytes[sizeof(hash) - 1 - i];
if ( hashstr != 0 )
init_hexbytes_noT(hashstr,hash.bytes,sizeof(hash));
return(hash);
}
char *bits256_str(char hexstr[65],bits256 x)
{
init_hexbytes_noT(hexstr,x.bytes,sizeof(x));
return(hexstr);
}
bits256 bits256_conv(char *hexstr)
{
bits256 x;
memset(&x,0,sizeof(x));
if ( strlen(hexstr) == sizeof(x)*2)
decode_hex(x.bytes,sizeof(x.bytes),hexstr);
return(x);
}
char *bits256_lstr(char hexstr[65],bits256 x)
{
bits256 revx; int32_t i;
for (i=0; i<32; i++)
revx.bytes[i] = x.bytes[31-i];
init_hexbytes_noT(hexstr,revx.bytes,sizeof(revx));
return(hexstr);
}
bits256 bits256_add(bits256 a,bits256 b)
{
int32_t i; bits256 sum; uint64_t x,carry = 0;
memset(sum.bytes,0,sizeof(sum));
for (i=0; i<4; i++)
{
x = a.ulongs[i] + b.ulongs[i];
sum.ulongs[i] = (x + carry);
if ( x < a.ulongs[i] || x < b.ulongs[i] )
carry = 1;
else carry = 0;
}
return(sum);
}
int32_t bits256_cmp(bits256 a,bits256 b)
{
int32_t i;
for (i=3; i>=0; i--)
{
//printf("%llx %llx, ",(long long)a.ulongs[i],(long long)b.ulongs[i]);
if ( a.ulongs[i] > b.ulongs[i] )
return(1);
else if ( a.ulongs[i] < b.ulongs[i] )
return(-1);
}
//printf("thesame\n");
return(0);
}
bits256 bits256_rshift(bits256 x)
{
int32_t i; uint64_t carry,prevcarry = 0;
for (i=3; i>=0; i--)
{
carry = (1 & x.ulongs[i]) << 63;
x.ulongs[i] = prevcarry | (x.ulongs[i] >> 1);
prevcarry = carry;
}
return(x);
}
bits256 bits256_lshift(bits256 x)
{
int32_t i,carry,prevcarry = 0; uint64_t mask = (1LL << 63);
for (i=0; i<4; i++)
{
carry = ((mask & x.ulongs[i]) != 0);
x.ulongs[i] = (x.ulongs[i] << 1) | prevcarry;
prevcarry = carry;
}
return(x);
}
bits256 bits256_ave(bits256 a,bits256 b)
{
return(bits256_rshift(bits256_add(a,b)));
}
bits256 bits256_from_compact(uint32_t c)
{
uint32_t nbytes,nbits,i; bits256 x;
memset(x.bytes,0,sizeof(x));
nbytes = (c >> 24) & 0xFF;
if ( nbytes >= 3 )
{
nbits = (8 * (nbytes - 3));
x.ulongs[0] = c & 0xFFFFFF;
for (i=0; i<nbits; i++)
x = bits256_lshift(x);
}
return(x);
}
uint32_t bits256_to_compact(bits256 x)
{
int32_t i; uint32_t nbits;
for (i=31; i>2; i--)
if ( x.bytes[i] != 0 )
break;
if ( (x.bytes[i] & 0x80) != 0 )
i++;
nbits = x.bytes[i] << 16;
nbits |= x.bytes[i-1] << 8;
nbits |= x.bytes[i-2];
nbits |= ((i+1) << 24);
return(nbits);
}
int32_t bitweight(uint64_t x)
{
int i,wt = 0;
for (i=0; i<64; i++)
if ( (1LL << i) & x )
wt++;
return(wt);
}
void calc_OP_HASH160(char hexstr[41],uint8_t rmd160[20],char *pubkey)
{
uint8_t buf[4096]; int32_t len;
len = (int32_t)strlen(pubkey)/2;
if ( len > sizeof(buf) )
{
printf("calc_OP_HASH160 overflow len.%d vs %d\n",len,(int32_t)sizeof(buf));
return;
}
decode_hex(buf,len,pubkey);
calc_rmd160_sha256(rmd160,buf,len);
if ( (0) )
{
int i;
for (i=0; i<20; i++)
printf("%02x",rmd160[i]);
printf("<- (%s)\n",pubkey);
}
if ( hexstr != 0 )
init_hexbytes_noT(hexstr,rmd160,20);
}
double _xblend(float *destp,double val,double decay)
{
double oldval;
if ( (oldval = *destp) != 0. )
return((oldval * decay) + ((1. - decay) * val));
else return(val);
}
double _dxblend(double *destp,double val,double decay)
{
double oldval;
if ( (oldval = *destp) != 0. )
return((oldval * decay) + ((1. - decay) * val));
else return(val);
}
double dxblend(double *destp,double val,double decay)
{
double newval,slope;
if ( isnan(*destp) != 0 )
*destp = 0.;
if ( isnan(val) != 0 )
return(0.);
if ( *destp == 0 )
{
*destp = val;
return(0);
}
newval = _dxblend(destp,val,decay);
if ( newval < SMALLVAL && newval > -SMALLVAL )
{
// non-zero marker for actual values close to or even equal to zero
if ( newval < 0. )
newval = -SMALLVAL;
else newval = SMALLVAL;
}
if ( *destp != 0. && newval != 0. )
slope = (newval - *destp);
else slope = 0.;
*destp = newval;
return(slope);
}
int32_t TerminateQ_queued; queue_t TerminateQ;
/*void iguana_terminator(void *arg)
{
struct iguana_thread *t; uint32_t lastdisp = 0; int32_t terminated = 0;
printf("iguana_terminator\n");
while ( 1 )
{
if ( (t= queue_dequeue(&TerminateQ,0)) != 0 )
{
printf("terminate.%p\n",t);
iguana_terminate(t);
terminated++;
continue;
}
sleep(1);
if ( time(NULL) > lastdisp+60 )
{
lastdisp = (uint32_t)time(NULL);
printf("TerminateQ %d terminated of %d queued\n",terminated,TerminateQ_queued);
}
}
}*/
int32_t iguana_numthreads(struct iguana_info *coin,int32_t mask)
{
int32_t i,sum = 0;
for (i=0; i<8; i++)
if ( ((1 << i) & mask) != 0 )
sum += (coin->Launched[i] - coin->Terminated[i]);
return(sum);
}
void iguana_launcher(void *ptr)
{
struct iguana_thread *t = ptr; //struct iguana_info *coin;
//coin = t->coin;
t->funcp(t->arg);
//if ( coin != 0 )
// coin->Terminated[t->type % (sizeof(coin->Terminated)/sizeof(*coin->Terminated))]++;
queue_enqueue("TerminateQ",&TerminateQ,&t->DL);
}
void iguana_terminate(struct iguana_thread *t)
{
int32_t retval;
#ifndef _WIN32
retval = pthread_join(t->handle,NULL);
if ( retval != 0 )
printf("error.%d terminating t.%p thread.%s\n",retval,t,t->name);
#endif
myfree(t,sizeof(*t));
}
struct iguana_thread *iguana_launch(struct iguana_info *coin,char *name,iguana_func funcp,void *arg,uint8_t type)
{
int32_t retval; struct iguana_thread *t;
t = mycalloc('Z',1,sizeof(*t));
strcpy(t->name,name);
t->coin = coin;
t->funcp = funcp;
t->arg = arg;
t->type = (type % (sizeof(coin->Terminated)/sizeof(*coin->Terminated)));
if ( coin != 0 )
coin->Launched[t->type]++;
retval = OS_thread_create(&t->handle,NULL,(void *)iguana_launcher,(void *)t);
if ( retval != 0 )
printf("error launching %s\n",t->name);
while ( (t= queue_dequeue(&TerminateQ)) != 0 )
{
if ( (rand() % 100000) == 0 && coin != 0 )
printf("terminated.%d launched.%d terminate.%p\n",coin->Terminated[t->type],coin->Launched[t->type],t);
iguana_terminate(t);
}
return(t);
}
char hexbyte(int32_t c)
{
c &= 0xf;
if ( c < 10 )
return('0'+c);
else if ( c < 16 )
return('a'+c-10);
else return(0);
}
int32_t _unhex(char c)
{
if ( c >= '0' && c <= '9' )
return(c - '0');
else if ( c >= 'a' && c <= 'f' )
return(c - 'a' + 10);
else if ( c >= 'A' && c <= 'F' )
return(c - 'A' + 10);
return(-1);
}
int32_t is_hexstr(char *str,int32_t n)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return(0);
for (i=0; str[i]!=0; i++)
{
if ( n > 0 && i >= n )
break;
if ( _unhex(str[i]) < 0 )
break;
}
if ( n == 0 )
return(i);
return(i == n);
}
int32_t unhex(char c)
{
int32_t hex;
if ( (hex= _unhex(c)) < 0 )
{
//printf("unhex: illegal hexchar.(%c)\n",c);
}
return(hex);
}
unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); }
int32_t decode_hex(unsigned char *bytes,int32_t n,char *hex)
{
int32_t adjust,i = 0;
//printf("decode.(%s)\n",hex);
if ( is_hexstr(hex,n) <= 0 )
{
memset(bytes,0,n);
return(n);
}
if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
hex[--n] = 0;
if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
hex[--n] = 0;
if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) )
{
if ( n > 0 )
{
bytes[0] = unhex(hex[0]);
printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex));
}
bytes++;
hex++;
adjust = 1;
} else adjust = 0;
if ( n > 0 )
{
for (i=0; i<n; i++)
bytes[i] = _decode_hex(&hex[i*2]);
}
//bytes[i] = 0;
return(n + adjust);
}
int32_t init_hexbytes_noT(char *hexbytes,unsigned char *message,long len)
{
int32_t i;
if ( len <= 0 )
{
hexbytes[0] = 0;
return(1);
}
for (i=0; i<len; i++)
{
hexbytes[i*2] = hexbyte((message[i]>>4) & 0xf);
hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf);
//printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]);
}
hexbytes[len*2] = 0;
//printf("len.%ld\n",len*2+1);
return((int32_t)len*2+1);
}
long _stripwhite(char *buf,int accept)
{
int32_t i,j,c;
if ( buf == 0 || buf[0] == 0 )
return(0);
for (i=j=0; buf[i]!=0; i++)
{
buf[j] = c = buf[i];
if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') )
j++;
}
buf[j] = 0;
return(j);
}
char *clonestr(char *str)
{
char *clone;
if ( str == 0 || str[0] == 0 )
{
printf("warning cloning nullstr.%p\n",str);
//#ifdef __APPLE__
// while ( 1 ) sleep(1);
//#endif
str = (char *)"<nullstr>";
}
clone = (char *)malloc(strlen(str)+16);
strcpy(clone,str);
return(clone);
}
int32_t safecopy(char *dest,char *src,long len)
{
int32_t i = -1;
if ( src != 0 && dest != 0 && src != dest )
{
if ( dest != 0 )
memset(dest,0,len);
for (i=0; i<len&&src[i]!=0; i++)
dest[i] = src[i];
if ( i == len )
{
printf("safecopy: %s too long %ld\n",src,len);
#ifdef __APPLE__
//getchar();
#endif
return(-1);
}
dest[i] = 0;
}
return(i);
}
void escape_code(char *escaped,char *str)
{
int32_t i,j,c; char esc[16];
for (i=j=0; str[i]!=0; i++)
{
if ( ((c= str[i]) >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') )
escaped[j++] = c;
else
{
sprintf(esc,"%%%02X",c);
//sprintf(esc,"\\\\%c",c);
strcpy(escaped + j,esc);
j += strlen(esc);
}
}
escaped[j] = 0;
//printf("escape_code: (%s) -> (%s)\n",str,escaped);
}
int32_t is_zeroes(char *str)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return(1);
for (i=0; str[i]!=0; i++)
if ( str[i] != '0' )
return(0);
return(1);
}
int64_t conv_floatstr(char *numstr)
{
double val,corr;
val = atof(numstr);
corr = (val < 0.) ? -0.50000000001 : 0.50000000001;
return((int64_t)(val * SATOSHIDEN + corr));
}
int32_t has_backslash(char *str)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return(0);
for (i=0; str[i]!=0; i++)
if ( str[i] == '\\' )
return(1);
return(0);
}
static int _increasing_double(const void *a,const void *b)
{
#define double_a (*(double *)a)
#define double_b (*(double *)b)
if ( double_b > double_a )
return(-1);
else if ( double_b < double_a )
return(1);
return(0);
#undef double_a
#undef double_b
}
int _increasing_uint64(const void *a,const void *b)
{
#define uint64_a (*(uint64_t *)a)
#define uint64_b (*(uint64_t *)b)
if ( uint64_b > uint64_a )
return(-1);
else if ( uint64_b < uint64_a )
return(1);
return(0);
#undef uint64_a
#undef uint64_b
}
static int _decreasing_uint64(const void *a,const void *b)
{
#define uint64_a (*(uint64_t *)a)
#define uint64_b (*(uint64_t *)b)
if ( uint64_b > uint64_a )
return(1);
else if ( uint64_b < uint64_a )
return(-1);
return(0);
#undef uint64_a
#undef uint64_b
}
static int _decreasing_uint32(const void *a,const void *b)
{
#define uint32_a (*(uint32_t *)a)
#define uint32_b (*(uint32_t *)b)
if ( uint32_b > uint32_a )
return(1);
else if ( uint32_b < uint32_a )
return(-1);
return(0);
#undef uint32_a
#undef uint32_b
}
int32_t sortds(double *buf,uint32_t num,int32_t size)
{
qsort(buf,num,size,_increasing_double);
return(0);
}
int32_t sort64s(uint64_t *buf,uint32_t num,int32_t size)
{
qsort(buf,num,size,_increasing_uint64);
return(0);
}
int32_t revsort64s(uint64_t *buf,uint32_t num,int32_t size)
{
qsort(buf,num,size,_decreasing_uint64);
return(0);
}
int32_t revsort32(uint32_t *buf,uint32_t num,int32_t size)
{
qsort(buf,num,size,_decreasing_uint32);
return(0);
}
/*int32_t iguana_sortbignum(void *buf,int32_t size,uint32_t num,int32_t structsize,int32_t dir)
{
int32_t retval = 0;
if ( dir > 0 )
{
if ( size == 32 )
qsort(buf,num,structsize,_increasing_bits256);
else if ( size == 20 )
qsort(buf,num,structsize,_increasing_rmd160);
else retval = -1;
}
else
{
if ( size == 32 )
qsort(buf,num,structsize,_decreasing_bits256);
else if ( size == 20 )
qsort(buf,num,structsize,_decreasing_rmd160);
else retval = -1;
}
if ( retval < 0 )
printf("iguana_sortbignum only does bits256 and rmd160 for now\n");
return(retval);
}*/
void touppercase(char *str)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return;
for (i=0; str[i]!=0; i++)
str[i] = toupper(((int32_t)str[i]));
}
void tolowercase(char *str)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return;
for (i=0; str[i]!=0; i++)
str[i] = tolower(((int32_t)str[i]));
}
char *uppercase_str(char *buf,char *str)
{
if ( str != 0 )
{
strcpy(buf,str);
touppercase(buf);
} else buf[0] = 0;
return(buf);
}
char *lowercase_str(char *buf,char *str)
{
if ( str != 0 )
{
strcpy(buf,str);
tolowercase(buf);
} else buf[0] = 0;
return(buf);
}
int32_t strsearch(char *strs[],int32_t num,char *name)
{
int32_t i; char strA[32],refstr[32];
strcpy(refstr,name), touppercase(refstr);
for (i=0; i<num; i++)
{
strcpy(strA,strs[i]), touppercase(strA);
if ( strcmp(strA,refstr) == 0 )
return(i);
}
return(-1);
}
int32_t is_decimalstr(char *str)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return(0);
for (i=0; str[i]!=0; i++)
if ( str[i] < '0' || str[i] > '9' )
return(0);
return(i);
}
int32_t unstringbits(char *buf,uint64_t bits)
{
int32_t i;
for (i=0; i<8; i++,bits>>=8)
if ( (buf[i]= (char)(bits & 0xff)) == 0 )
break;
buf[i] = 0;
return(i);
}
uint64_t stringbits(char *str)
{
uint64_t bits = 0;
if ( str == 0 )
return(0);
int32_t i,n = (int32_t)strlen(str);
if ( n > 8 )
n = 8;
for (i=n-1; i>=0; i--)
bits = (bits << 8) | (str[i] & 0xff);
//printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
return(bits);
}
char *unstringify(char *str)
{
int32_t i,j,n;
if ( str == 0 )
return(0);
else if ( str[0] == 0 )
return(str);
n = (int32_t)strlen(str);
if ( str[0] == '"' && str[n-1] == '"' )
str[n-1] = 0, i = 1;
else i = 0;
for (j=0; str[i]!=0; i++)
{
if ( str[i] == '\\' && (str[i+1] == 't' || str[i+1] == 'n' || str[i+1] == 'b' || str[i+1] == 'r') )
i++;
else if ( str[i] == '\\' && str[i+1] == '"' )
str[j++] = '"', i++;
else str[j++] = str[i];
}
str[j] = 0;
return(str);
}
void reverse_hexstr(char *str)
{
int i,n;
char *rev;
n = (int32_t)strlen(str);
rev = (char *)malloc(n + 1);
for (i=0; i<n; i+=2)
{
rev[n-2-i] = str[i];
rev[n-1-i] = str[i+1];
}
rev[n] = 0;
strcpy(str,rev);
free(rev);
}
int32_t nn_base64_decode (const char *in, size_t in_len,uint8_t *out, size_t out_len)
{
uint32_t ii,io,rem,v; uint8_t ch;
// Unrolled lookup of ASCII code points. 0xFF represents a non-base64 valid character.
const uint8_t DECODEMAP [256] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF,
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
for (io = 0, ii = 0, v = 0, rem = 0; ii < in_len; ii++) {
if (isspace ((uint32_t)in [ii]))
continue;
if (in [ii] == '=')
break;
ch = DECODEMAP [(uint32_t)in [ii]];
// Discard invalid characters as per RFC 2045.
if (ch == 0xFF)
break;
v = (v << 6) | ch;
rem += 6;
if (rem >= 8) {
rem -= 8;
if (io >= out_len)
return -ENOBUFS;
out [io++] = (v >> rem) & 255;
}
}
if (rem >= 8) {
rem -= 8;
if (io >= out_len)
return -ENOBUFS;
out [io++] = (v >> rem) & 255;
}
return io;
}
int32_t nn_base64_encode (const uint8_t *in, size_t in_len,char *out, size_t out_len)
{
uint32_t ii,io,rem,v; uint8_t ch;
const uint8_t ENCODEMAP [64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
for (io = 0, ii = 0, v = 0, rem = 0; ii < in_len; ii++) {
ch = in [ii];
v = (v << 8) | ch;
rem += 8;
while (rem >= 6) {
rem -= 6;
if (io >= out_len)
return -ENOBUFS;
out [io++] = ENCODEMAP [(v >> rem) & 63];
}
}
if (rem) {
v <<= (6 - rem);
if (io >= out_len)
return -ENOBUFS;
out [io++] = ENCODEMAP [v & 63];
}
// Pad to a multiple of 3
while (io & 3) {
if (io >= out_len)
return -ENOBUFS;
out [io++] = '=';
}
if (io >= out_len)
return -ENOBUFS;
out [io] = '\0';
return io;
}
/*
NXT address converter,
Ported from original javascript (nxtchg)
To C by Jones
*/
int32_t gexp[] = {1, 2, 4, 8, 16, 5, 10, 20, 13, 26, 17, 7, 14, 28, 29, 31, 27, 19, 3, 6, 12, 24, 21, 15, 30, 25, 23, 11, 22, 9, 18, 1};
int32_t glog[] = {0, 0, 1, 18, 2, 5, 19, 11, 3, 29, 6, 27, 20, 8, 12, 23, 4, 10, 30, 17, 7, 22, 28, 26, 21, 25, 9, 16, 13, 14, 24, 15};
int32_t cwmap[] = {3, 2, 1, 0, 7, 6, 5, 4, 13, 14, 15, 16, 12, 8, 9, 10, 11};
char alphabet[] = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
int32_t gmult(int32_t a,int32_t b)
{
if ( a == 0 || b == 0 )
return 0;
int32_t idx = (glog[a] + glog[b]) % 31;
return gexp[idx];
}
int32_t letterval(char letter)
{
int32_t ret = 0;
if ( letter < '9' )
ret = letter - '2';
else
{
ret = letter - 'A' + 8;
if ( letter > 'I' )
ret--;
if ( letter > 'O' )
ret--;
}
return ret;
}
uint64_t RS_decode(char *rs)
{
int32_t code[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int32_t i,p = 4;
if ( strncmp("NXT-",rs,4) != 0 )
return(0);
for (i=0; i<17; i++)
{
code[cwmap[i]] = letterval(rs[p]);
p++;
if ( rs[p] == '-' )
p++;
}
uint64_t out = 0;
for (i=12; i>=0; i--)
out = out * 32 + code[i];
return out;
}
int32_t RS_encode(char *rsaddr,uint64_t id)
{
int32_t a,code[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int32_t inp[32],out[32],i,j,fb,pos = 0,len = 0;
char acc[64];
rsaddr[0] = 0;
memset(inp,0,sizeof(inp));
memset(out,0,sizeof(out));
memset(acc,0,sizeof(acc));
expand_nxt64bits(acc,id);
//sprintf(acc,"%llu",(long long)id);
for (a=0; *(acc+a) != '\0'; a++)
len++;
if ( len == 20 && *acc != '1' )
{
printf("error (%s) doesnt start with 1",acc);
return(-1);
}
for (i=0; i<len; i++)
inp[i] = (int32_t)*(acc+i) - (int32_t)'0';
int32_t divide = 0;
int32_t newlen = 0;
do // base 10 to base 32 conversion
{
divide = 0;
newlen = 0;
for (i=0; i<len; i++)
{
divide = divide * 10 + inp[i];
if (divide >= 32)
{
inp[newlen++] = divide >> 5;
divide &= 31;
}
else if ( newlen > 0 )
inp[newlen++] = 0;
}
len = newlen;
out[pos++] = divide;
} while ( newlen != 0 );
for (i=0; i<13; i++) // copy to code in reverse, pad with 0's
code[i] = (--pos >= 0 ? out[i] : 0);
int32_t p[] = {0, 0, 0, 0};
for (i=12; i>=0; i--)
{
fb = code[i] ^ p[3];
p[3] = p[2] ^ gmult(30, fb);
p[2] = p[1] ^ gmult(6, fb);
p[1] = p[0] ^ gmult(9, fb);
p[0] = gmult(17, fb);
}
code[13] = p[0];
code[14] = p[1];
code[15] = p[2];
code[16] = p[3];
strcpy(rsaddr,"NXT-");
j=4;
for (i=0; i<17; i++)
{
rsaddr[j++] = alphabet[code[cwmap[i]]];
if ( (j % 5) == 3 && j < 20 )
rsaddr[j++] = '-';
}
rsaddr[j] = 0;
return(0);
}
uint64_t conv_acctstr(char *acctstr)
{
uint64_t nxt64bits = 0;
int32_t len;
if ( acctstr != 0 )
{
if ( (len= is_decimalstr(acctstr)) > 0 && len < 24 )
nxt64bits = calc_nxt64bits(acctstr);
else if ( strncmp("NXT-",acctstr,4) == 0 )
{
nxt64bits = RS_decode(acctstr);
//nxt64bits = conv_rsacctstr(acctstr,0);
}
}
return(nxt64bits);
}
int32_t base32byte(int32_t val)
{
if ( val < 26 )
return('A' + val);
else if ( val < 32 )
return('2' + val - 26);
else return(-1);
}
int32_t unbase32(char c)
{
if ( c >= 'A' && c <= 'Z' )
return(c - 'A');
else if ( c >= '2' && c <= '7' )
return(c - '2' + 26);
else return(-1);
}
int init_base32(char *tokenstr,uint8_t *token,int32_t len)
{
int32_t i,j,n,val5,offset = 0;
for (i=n=0; i<len; i++)
{
for (j=val5=0; j<5; j++,offset++)
if ( GETBIT(token,offset) != 0 )
SETBIT(&val5,offset);
tokenstr[n++] = base32byte(val5);
}
tokenstr[n] = 0;
return(n);
}
int decode_base32(uint8_t *token,uint8_t *tokenstr,int32_t len)
{
int32_t i,j,n,val5,offset = 0;
for (i=n=0; i<len; i++)
{
if ( (val5= unbase32(tokenstr[i])) >= 0 )
{
for (j=val5=0; j<5; j++,offset++)
{
if ( GETBIT(&val5,j) != 0 )
SETBIT(token,offset);
else CLEARBIT(token,offset);
}
} else return(-1);
}
while ( (offset & 7) != 0 )
{
CLEARBIT(token,offset);
offset++;
}
return(offset);
}
void calc_hexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
init_hexbytes_noT(hexstr,(void *)msg,len+1);
}
void calc_unhexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
decode_hex((void *)hexstr,len>>1,(void *)msg);
hexstr[len>>1] = 0;
}
void calc_base64_encodestr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
nn_base64_encode(msg,len,hexstr,len);
}
void calc_base64_decodestr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
nn_base64_decode((void *)msg,len,(void *)hexstr,1024);
}
void sha256_sha256(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
bits256_doublesha256(hexstr,msg,len);
}
void rmd160ofsha256(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
uint8_t sha256[32];
if ( is_hexstr((char *)msg,len) > 0 )
{
decode_hex((uint8_t *)hexstr,len/2,(char *)msg);
vcalc_sha256(0,sha256,(void *)hexstr,len/2);
calc_rmd160(hexstr,buf,sha256,sizeof(sha256));
} else vcalc_sha256(0,sha256,(void *)msg,len);
calc_rmd160(hexstr,buf,sha256,sizeof(sha256));
}
void calc_md2str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
bits128 x;
calc_md2(hexstr,buf,msg,len);
decode_hex(buf,sizeof(x),hexstr);
//memcpy(buf,x.bytes,sizeof(x));
}
void calc_md4str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
bits128 x;
calc_md4(hexstr,buf,msg,len);
decode_hex(buf,sizeof(x),hexstr);
//memcpy(buf,x.bytes,sizeof(x));
}
void calc_md5str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
bits128 x;
calc_md5(hexstr,msg,len);
decode_hex(buf,sizeof(x),hexstr);
//memcpy(buf,x.bytes,sizeof(x));
}
void calc_crc32str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
uint32_t crc; uint8_t serialized[sizeof(crc)];
crc = calc_crc32(0,msg,len);
//iguana_rwnum(1,serialized,sizeof(crc),&crc);
serialized[3] = (crc & 0xff), crc >>= 8;
serialized[2] = (crc & 0xff), crc >>= 8;
serialized[1] = (crc & 0xff), crc >>= 8;
serialized[0] = (crc & 0xff), crc >>= 8;
init_hexbytes_noT(hexstr,serialized,sizeof(crc));
//printf("crc.%08x vs revcrc.%08x -> %s\n",crc,*(uint32_t *)serialized,hexstr);
}
void calc_NXTaddr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
uint8_t mysecret[32]; uint64_t nxt64bits;
nxt64bits = conv_NXTpassword(mysecret,buf,msg,len);
RS_encode(hexstr,nxt64bits);
}
void calc_curve25519_str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
bits256 x,priv,pub;
if ( len != sizeof(bits256)*2 || is_hexstr((char *)msg,64) == 0 )
conv_NXTpassword(priv.bytes,pub.bytes,msg,len);
else priv = *(bits256 *)msg;
x = curve25519(priv,curve25519_basepoint9());
init_hexbytes_noT(hexstr,x.bytes,sizeof(x));
}
void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen)
{
bits256 hash;
vcalc_sha256(0,hash.bytes,data,datalen);
calc_rmd160(0,rmd160,hash.bytes,sizeof(hash));
}
char *cmc_ticker(char *base)
{
char url[512];
sprintf(url,"https://api.coinmarketcap.com/v1/ticker/%s/",base);
return(issue_curl(url));
}
char *bittrex_orderbook(char *base,char *rel,int32_t maxdepth)
{
char market[64],url[512];
sprintf(market,"%s-%s",rel,base);
sprintf(url,"http://bittrex.com/api/v1.1/public/getorderbook?market=%s&type=both&depth=%d",market,maxdepth);
return(issue_curl(url));
}
double calc_theoretical(double weighted,double CMC_average,double changes[3])
{
double theoretical = 0.; //adjusted = 0.,
if ( weighted > SMALLVAL && CMC_average > SMALLVAL )
{
theoretical = (weighted + CMC_average) * 0.5;
/*if ( changes[0] > SMALLVAL && changes[1] > SMALLVAL && changes[2] > SMALLVAL )
{
if ( changes[0] > changes[1] && changes[1] > changes[2] ) // breakout
{
adjusted = theoretical * (1. - (changes[0] + changes[1]) * .005);
}
}
else if ( changes[0] < -SMALLVAL && changes[1] < -SMALLVAL && changes[2] < -SMALLVAL ) //
{
if ( changes[0] < changes[1] && changes[1] < changes[2] ) // waterfall
{
adjusted = theoretical * (1. - (changes[0] + changes[1]) * .005);
}
}
if ( adjusted != 0. && theoretical != 0. )
theoretical = (theoretical + adjusted) * 0.5;*/
}
//printf("adjusted %.8f theoretical %.8f (%.8f + wt %.8f)\n",adjusted,theoretical,CMC_average,weighted);
return(theoretical);
}
double calc_weighted(double *avebidp,double *aveaskp,double *bids,double *bidvols,int32_t numbids,double *asks,double *askvols,int32_t numasks,double limit)
{
int32_t i; double weighted = 0.,bidsum = 0., asksum = 0.,totalbids = 0.,totalasks = 0.;
bidsum = bids[0] * bidvols[0], totalbids = bidvols[0];
asksum = asks[0] * askvols[0], totalasks = askvols[0];
for (i=1; i<numbids; i++)
{
if ( totalbids > limit )
break;
bidsum += bids[i] * bidvols[i];
totalbids += bidvols[i];
}
for (i=1; i<numasks; i++)
{
if ( totalasks > limit )
break;
asksum += asks[i] * askvols[i];
totalasks += askvols[i];
}
if ( totalbids != 0. && totalasks != 0. )
{
*avebidp = (bidsum / totalbids);
*aveaskp = (asksum / totalasks);
weighted = (*avebidp + *aveaskp) * 0.5;
}
//printf("weighted %f\n",weighted);
return(weighted);
}
double weighted_orderbook(double *avebidp,double *aveaskp,double *highbidp,double *lowaskp,char *orderbookstr,double limit)
{
cJSON *bookjson,*bid,*ask,*resobj,*item; int32_t i,numbids,numasks; double bidvols[50],bids[50],askvols[50],asks[50],weighted = 0.;
if ( orderbookstr != 0 )
{
if ( (bookjson= cJSON_Parse(orderbookstr)) != 0 )
{
if ( (resobj= jobj(bookjson,"result")) != 0 )
{
bid = jarray(&numbids,resobj,"buy");
if ( numbids > sizeof(bids)/sizeof(*bids) )
numbids = (int32_t)(sizeof(bids)/sizeof(*bids));
ask = jarray(&numasks,resobj,"sell");
if ( numasks > sizeof(asks)/sizeof(*asks) )
numasks = (int32_t)(sizeof(asks)/sizeof(*asks));
if ( bid != 0 && ask != 0 )
{
for (i=0; i<numbids; i++)
{
item = jitem(bid,i);
bidvols[i] = jdouble(item,"Quantity");
bids[i] = jdouble(item,"Rate");
}
for (i=0; i<numasks; i++)
{
item = jitem(ask,i);
askvols[i] = jdouble(item,"Quantity");
asks[i] = jdouble(item,"Rate");
}
*highbidp = bids[0];
*lowaskp = asks[0];
weighted = calc_weighted(avebidp,aveaskp,bids,bidvols,numbids,asks,askvols,numasks,limit);
//printf("weighted %.8f (%.8f %.8f)\n",weighted,*highbidp,*lowaskp);
}
}
free_json(bookjson);
}
}
return(weighted);
}
double get_theoretical(double *avebidp,double *aveaskp,double *highbidp,double *lowaskp,double *CMC_averagep,double changes[3],char *name,char *base,char *rel,double *USD_averagep)
{
static int32_t counter;
char *cmcstr; cJSON *cmcjson,*item; double weighted,theoretical = 0.;
*avebidp = *aveaskp = *highbidp = *lowaskp = *CMC_averagep = 0.;
if ( (cmcstr= cmc_ticker(name)) != 0 )
{
if ( (cmcjson= cJSON_Parse(cmcstr)) != 0 )
{
if ( is_cJSON_Array(cmcjson) == 0 )
item = cmcjson;
else item = jitem(cmcjson,0);
*CMC_averagep = jdouble(item,"price_btc");
*USD_averagep = jdouble(item,"price_usd");
changes[0] = jdouble(item,"percent_change_1h");
changes[1] = jdouble(item,"percent_change_24h");
changes[2] = jdouble(item,"percent_change_7d");
weighted = weighted_orderbook(avebidp,aveaskp,highbidp,lowaskp,bittrex_orderbook(base,rel,25),1./(*CMC_averagep));
if ( *CMC_averagep > SMALLVAL && weighted > SMALLVAL )
theoretical = calc_theoretical(weighted,*CMC_averagep,changes);
if ( (0) && counter++ < 100 )
printf("HBLA.[%.8f %.8f] AVE.[%.8f %.8f] (%s) CMC %f %f %f %f\n",*highbidp,*lowaskp,*avebidp,*aveaskp,jprint(item,0),*CMC_averagep,changes[0],changes[1],changes[2]);
free_json(cmcjson);
}
free(cmcstr);
}
return(theoretical);
}