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.
1124 lines
51 KiB
1124 lines
51 KiB
|
|
/******************************************************************************
|
|
* Copyright © 2014-2018 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. *
|
|
* *
|
|
******************************************************************************/
|
|
//
|
|
// LP_utxos.c
|
|
// marketmaker
|
|
//
|
|
|
|
int32_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 myprivkey,bits256 mypub)
|
|
{
|
|
int32_t enable_utxos = 0;
|
|
char *script,destaddr[64]; cJSON *array,*item; bits256 txid,deposittxid,zero; int32_t used,i,flag=0,height,n,cmpflag,iambob,vout,depositvout; uint64_t *values=0,satoshis,txfee,biggerval,value,total = 0; int64_t targetval; //struct LP_utxoinfo *utxo;
|
|
if ( coin == 0 || (IAMLP == 0 && coin->inactive != 0) )
|
|
{
|
|
//printf("coin not active\n");
|
|
return(0);
|
|
}
|
|
if ( coin->privkeydepth > 0 )
|
|
return(0);
|
|
coin->privkeydepth++;
|
|
LP_address(coin,coin->smartaddr);
|
|
//if ( coin->inactive == 0 )
|
|
// LP_listunspent_issue(coin->symbol,coin->smartaddr,0);
|
|
memset(zero.bytes,0,sizeof(zero));
|
|
array = LP_listunspent(coin->symbol,coin->smartaddr,zero,zero);
|
|
if ( array != 0 )
|
|
{
|
|
txfee = LP_txfeecalc(coin,0,0);
|
|
if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
|
|
{
|
|
coin->numutxos = n;
|
|
//printf("LP_privkey_init %s %d\n",coin->symbol,n);
|
|
for (iambob=0; iambob<=1; iambob++)
|
|
{
|
|
if ( iambob == 0 )
|
|
values = calloc(n,sizeof(*values));
|
|
else memset(values,0,n * sizeof(*values));
|
|
used = 0;
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
value = LP_listunspent_parseitem(coin,&txid,&vout,&height,item);
|
|
satoshis = LP_txvalue(destaddr,coin->symbol,txid,vout);
|
|
if ( satoshis != 0 && satoshis != value )
|
|
printf("%s %s privkey_init value %.8f vs %.8f (%s) %.8f %.8f\n",coin->symbol,coin->smartaddr,dstr(satoshis),dstr(value),jprint(item,0),jdouble(item,"amount"),jdouble(item,"interest"));
|
|
if ( coin->electrum != 0 || LP_inventory_prevent(iambob,coin->symbol,txid,vout) == 0 )//&& height > 0 )
|
|
{
|
|
values[i] = satoshis;
|
|
//flag += LP_address_utxoadd(coin,destaddr,txid,vout,satoshis,height,-1);
|
|
} else used++;
|
|
}
|
|
//printf("array.%d\n",n);
|
|
while ( used < n-1 )
|
|
{
|
|
//for (i=0; i<n; i++)
|
|
// printf("%.8f ",dstr(values[i]));
|
|
//printf("used.%d of n.%d\n",used,n);
|
|
if ( (i= LP_maxvalue(values,n)) >= 0 )
|
|
{
|
|
item = jitem(array,i);
|
|
if ( coin->electrum == 0 )
|
|
{
|
|
deposittxid = jbits256(item,"txid");
|
|
depositvout = juint(item,"vout");
|
|
script = jstr(item,"scriptPubKey");
|
|
}
|
|
else
|
|
{
|
|
deposittxid = jbits256(item,"tx_hash");
|
|
depositvout = juint(item,"tx_pos");
|
|
script = coin->smartaddr;
|
|
}
|
|
biggerval = values[i];
|
|
values[i] = 0, used++;
|
|
if ( iambob == 0 )
|
|
targetval = (biggerval / 776) + txfee;
|
|
else targetval = (biggerval / 9) * 8 + 2*txfee;
|
|
if ( targetval < txfee*2 )
|
|
targetval = txfee*2;
|
|
//printf("iambob.%d i.%d deposit %.8f min %.8f target %.8f\n",iambob,i,dstr(biggerval),dstr((1+LP_MINSIZE_TXFEEMULT)*txfee),dstr(targetval));
|
|
if ( biggerval < (1+LP_MINSIZE_TXFEEMULT)*txfee )
|
|
continue;
|
|
i = -1;
|
|
if ( iambob != 0 )
|
|
{
|
|
if ( (i= LP_nearestvalue(iambob,values,n,targetval)) < 0 )
|
|
targetval /= 4;
|
|
if ( targetval < txfee*(1+LP_MINSIZE_TXFEEMULT) )
|
|
continue;
|
|
}
|
|
if ( i >= 0 || (i= LP_nearestvalue(iambob,values,n,targetval)) >= 0 )
|
|
{
|
|
//printf("iambob.%d i.%d %.8f target %.8f\n",iambob,i,dstr(biggerval),dstr(targetval));
|
|
item = jitem(array,i);
|
|
cmpflag = 0;
|
|
if ( coin->electrum == 0 )
|
|
{
|
|
txid = jbits256(item,"txid");
|
|
vout = juint(item,"vout");
|
|
if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 )
|
|
cmpflag = 1;
|
|
}
|
|
else
|
|
{
|
|
txid = jbits256(item,"tx_hash");
|
|
vout = juint(item,"tx_pos");
|
|
cmpflag = 1;
|
|
}
|
|
if ( cmpflag != 0 )
|
|
{
|
|
value = values[i];
|
|
values[i] = 0, used++;
|
|
/*portable_mutex_lock(&LP_UTXOmutex);
|
|
if ( iambob != 0 )
|
|
{
|
|
if ( (utxo= LP_utxoadd(1,coin->symbol,txid,vout,value,deposittxid,depositvout,biggerval,coin->smartaddr,mypub,LP_gui,G.LP_sessionid,value)) != 0 )
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//printf("call utxoadd\n");
|
|
if ( (utxo= LP_utxoadd(0,coin->symbol,deposittxid,depositvout,biggerval,txid,vout,value,coin->smartaddr,mypub,LP_gui,G.LP_sessionid,biggerval)) != 0 )
|
|
{
|
|
}
|
|
}
|
|
portable_mutex_unlock(&LP_UTXOmutex);*/
|
|
total += value;
|
|
} // else printf("scriptmismatch.(%s) vs %s\n",script,jprint(item,0));
|
|
} //else printf("nothing near i.%d\n",i);
|
|
} else break;
|
|
}
|
|
if ( enable_utxos == 0 )
|
|
break;
|
|
}
|
|
}
|
|
free_json(array);
|
|
if ( 0 && flag != 0 )
|
|
LP_postutxos(coin->symbol,coin->smartaddr);
|
|
}
|
|
if ( values != 0 )
|
|
free(values);
|
|
if ( coin->privkeydepth > 0 )
|
|
coin->privkeydepth--;
|
|
//printf("privkey.%s %.8f\n",symbol,dstr(total));
|
|
return(flag);
|
|
}
|
|
|
|
char *LP_secretaddresses(void *ctx,char *prefix,char *passphrase,int32_t n,uint8_t taddr,uint8_t pubtype)
|
|
{
|
|
int32_t i; uint8_t tmptype,pubkey33[33],rmd160[20]; char output[777*45],str[65],str2[65],buf[8192],wifstr[128],coinaddr[64]; bits256 checkprivkey,privkey,pubkey; cJSON *retjson;
|
|
retjson = cJSON_CreateObject();
|
|
if ( prefix == 0 || prefix[0] == 0 )
|
|
prefix = "secretaddress";
|
|
if ( passphrase == 0 || passphrase[0] == 0 )
|
|
passphrase = "password";
|
|
if ( n <= 0 )
|
|
n = 16;
|
|
else if ( n > 777 )
|
|
n = 777;
|
|
conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
bitcoin_priv2pub(ctx,"KMD",pubkey33,coinaddr,privkey,taddr,pubtype);
|
|
printf("generator (%s) secrets.[%d] <%s> t.%u p.%u\n",coinaddr,n,passphrase,taddr,pubtype);
|
|
sprintf(output,"\"addresses\":[");
|
|
for (i=0; i<n; i++)
|
|
{
|
|
sprintf(buf,"%s %s %03d",prefix,passphrase,i);
|
|
conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)buf,(int32_t)strlen(buf));
|
|
bitcoin_priv2pub(ctx,"KMD",pubkey33,coinaddr,privkey,taddr,pubtype);
|
|
bitcoin_priv2wif("KMD",0,wifstr,privkey,188);
|
|
bitcoin_wif2priv("KMD",0,&tmptype,&checkprivkey,wifstr);
|
|
bitcoin_addr2rmd160("KMD",taddr,&tmptype,rmd160,coinaddr);
|
|
if ( bits256_cmp(checkprivkey,privkey) != 0 )
|
|
{
|
|
printf("WIF.(%s) error -> %s vs %s?\n",wifstr,bits256_str(str,privkey),bits256_str(str2,checkprivkey));
|
|
free_json(retjson);
|
|
return(clonestr("{\"error\":\"couldnt validate wifstr\"}"));
|
|
}
|
|
else if ( tmptype != pubtype )
|
|
{
|
|
printf("checktype.%d != pubtype.%d\n",tmptype,pubtype);
|
|
free_json(retjson);
|
|
return(clonestr("{\"error\":\"couldnt validate pubtype\"}"));
|
|
}
|
|
jaddstr(retjson,coinaddr,wifstr);
|
|
sprintf(output+strlen(output),"\\\"%s\\\"%c ",coinaddr,i<n-1?',':' ');
|
|
printf("./komodo-cli jumblr_secret %s\n",coinaddr);
|
|
}
|
|
printf("%s]\n",output);
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
uint32_t komodo_segid32(char *coinaddr)
|
|
{
|
|
bits256 addrhash;
|
|
vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)coinaddr,(int32_t)strlen(coinaddr));
|
|
return(addrhash.uints[0]);
|
|
}
|
|
|
|
char *LP_gen64addrs(void *ctx,char *passphrase,uint8_t taddr,uint8_t pubtype)
|
|
{
|
|
int32_t i,segid,n=64; uint8_t tmptype,pubkey33[33],rmd160[20]; char str[65],str2[65],buf[8192],wifstr[64],coinaddr[64],coinaddrs[64][64],wifstrs[64][64]; uint64_t mask = 0; bits256 checkprivkey,privkey,pubkey; cJSON *retjson,*addrs,*array;
|
|
if ( passphrase == 0 || passphrase[0] == 0 )
|
|
passphrase = "password";
|
|
memset(coinaddrs,0,sizeof(coinaddrs));
|
|
memset(wifstrs,0,sizeof(wifstrs));
|
|
conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
bitcoin_priv2pub(ctx,"KMD",pubkey33,coinaddr,privkey,taddr,pubtype);
|
|
//sprintf(output,"\"addresses\":[");
|
|
for (i=0; bitweight(mask)<64; i++)
|
|
{
|
|
sprintf(buf,"%s %03d",passphrase,i);
|
|
conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)buf,(int32_t)strlen(buf));
|
|
bitcoin_priv2pub(ctx,"KMD",pubkey33,coinaddr,privkey,taddr,pubtype);
|
|
bitcoin_priv2wif("KMD",0,wifstr,privkey,188);
|
|
bitcoin_wif2priv("KMD",0,&tmptype,&checkprivkey,wifstr);
|
|
bitcoin_addr2rmd160("KMD",taddr,&tmptype,rmd160,coinaddr);
|
|
if ( bits256_cmp(checkprivkey,privkey) != 0 )
|
|
{
|
|
printf("WIF.(%s) error -> %s vs %s?\n",wifstr,bits256_str(str,privkey),bits256_str(str2,checkprivkey));
|
|
free_json(retjson);
|
|
return(clonestr("{\"error\":\"couldnt validate wifstr\"}"));
|
|
}
|
|
else if ( tmptype != pubtype )
|
|
{
|
|
printf("checktype.%d != pubtype.%d\n",tmptype,pubtype);
|
|
free_json(retjson);
|
|
return(clonestr("{\"error\":\"couldnt validate pubtype\"}"));
|
|
}
|
|
segid = komodo_segid32(coinaddr) & 0x3f;
|
|
if ( (mask & (1LL << segid)) == 0 )
|
|
{
|
|
mask |= (1LL << segid);
|
|
strcpy(coinaddrs[segid],coinaddr);
|
|
strcpy(wifstrs[segid],wifstr);
|
|
printf("./komodo-cli -ac_name=POSTEST64 importprivkey %s "" %s\n",wifstr,bitweight(mask)<64?"false":"true");
|
|
}
|
|
//sprintf(output+strlen(output),"\\\"%s\\\"%c ",coinaddr,i<n-1?',':' ');
|
|
}
|
|
retjson = cJSON_CreateObject();
|
|
addrs = cJSON_CreateObject();
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<n; i++)
|
|
jaddstr(addrs,coinaddrs[i],wifstrs[i]);
|
|
jadd(retjson,"addrpairs",addrs);
|
|
for (i=0; i<n; i++)
|
|
jaddistr(array,coinaddrs[i]);
|
|
jadd(retjson,"addresses",array);
|
|
//printf("%s]\n",output);
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
static const char base58_chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
|
|
int32_t LP_wifstr_valid(char *symbol,char *wifstr)
|
|
{
|
|
bits256 privkey,cmpkey; uint8_t wiftype; char cmpstr[128],cmpstr2[128]; int32_t i,len,n,a,A;
|
|
if ( (len= (int32_t)strlen(wifstr)) < 50 || len > 54 )
|
|
{
|
|
//printf("len.%d is wrong for wif %s\n",len,wifstr);
|
|
return(0);
|
|
}
|
|
memset(privkey.bytes,0,sizeof(privkey));
|
|
memset(cmpkey.bytes,0,sizeof(cmpkey));
|
|
for (i=n=a=A=0; wifstr[i]!=0; i++)
|
|
{
|
|
if ( strchr(base58_chars,wifstr[i]) == 0 )
|
|
return(0);
|
|
if ( wifstr[i] >= '1' && wifstr[i] <= '9' )
|
|
n++;
|
|
else if ( wifstr[i] >= 'A' && wifstr[i] <= 'Z' )
|
|
A++;
|
|
else if ( wifstr[i] >= 'a' && wifstr[i] <= 'z' )
|
|
a++;
|
|
}
|
|
if ( n == 0 || A == 0 || a == 0 )
|
|
return(0);
|
|
if ( A > 5*a || a > 5*A || a > n*26 || A > n*26 ) // unlikely it is a real wif
|
|
{
|
|
printf("reject wif %s due to n.%d a.%d A.%d (%d %d %d %d)\n",wifstr,n,a,A,A > 5*a,a < 5*A,a > n*20,A > n*20);
|
|
return(0);
|
|
}
|
|
bitcoin_wif2priv(symbol,0,&wiftype,&privkey,wifstr);
|
|
bitcoin_priv2wif(symbol,0,cmpstr,privkey,wiftype);
|
|
if ( strcmp(cmpstr,wifstr) == 0 )
|
|
{
|
|
//printf("%s is valid wif\n",wifstr);
|
|
return(1);
|
|
}
|
|
else if ( bits256_nonz(privkey) != 0 )
|
|
{
|
|
bitcoin_wif2priv(symbol,0,&wiftype,&cmpkey,cmpstr);
|
|
bitcoin_priv2wiflong(symbol,0,cmpstr2,privkey,wiftype);
|
|
if ( bits256_cmp(privkey,cmpkey) == 0 )
|
|
return(1);
|
|
char str[65],str2[65]; printf("%s mismatched wifstr %s -> %s -> %s %s %s\n",symbol,wifstr,bits256_str(str,privkey),cmpstr,bits256_str(str2,cmpkey),cmpstr2);
|
|
}
|
|
char str[65]; printf("%s is not a wif, privkey.%s\n",wifstr,bits256_str(str,privkey));
|
|
return(0);
|
|
}
|
|
|
|
char *LP_convaddress(char *symbol,char *address,char *dest)
|
|
{
|
|
struct iguana_info *coin,*destcoin; cJSON *retjson; char destaddress[64],coinaddr2[64]; uint8_t addrtype,rmd160[20],rmd160b[20];
|
|
if ( (coin= LP_coinfind(symbol)) == 0 || (destcoin= LP_coinfind(dest)) == 0 )
|
|
return(clonestr("{\"error\":\"both coins must be present\"}"));
|
|
retjson = cJSON_CreateObject();
|
|
jaddstr(retjson,"result","success");
|
|
jaddstr(retjson,"coin",symbol);
|
|
jaddstr(retjson,"address",address);
|
|
jaddstr(retjson,"destcoin",dest);
|
|
bitcoin_addr2rmd160(symbol,coin->taddr,&addrtype,rmd160,address);
|
|
if ( addrtype == coin->pubtype )
|
|
{
|
|
bitcoin_address(destcoin->symbol,destaddress,destcoin->taddr,destcoin->pubtype,rmd160,20);
|
|
bitcoin_addr2rmd160(destcoin->symbol,destcoin->taddr,&addrtype,rmd160b,destaddress);
|
|
bitcoin_address(coin->symbol,coinaddr2,coin->taddr,coin->pubtype,rmd160b,20);
|
|
}
|
|
else if ( addrtype == coin->p2shtype )
|
|
{
|
|
bitcoin_address(destcoin->symbol,destaddress,destcoin->taddr,destcoin->p2shtype,rmd160,20);
|
|
bitcoin_addr2rmd160(symbol,coin->taddr,&addrtype,rmd160b,destaddress);
|
|
bitcoin_address(destcoin->symbol,coinaddr2,coin->taddr,coin->p2shtype,rmd160b,20);
|
|
}
|
|
else
|
|
{
|
|
jaddstr(retjson,"error","invalid base58 prefix");
|
|
jaddnum(retjson,"invalid",addrtype);
|
|
}
|
|
if ( strcmp(address,coinaddr2) != 0 )
|
|
{
|
|
jaddstr(retjson,"error","checkaddress mismatch");
|
|
jaddstr(retjson,"checkaddress",coinaddr2);
|
|
}
|
|
jaddstr(retjson,"destaddress",destaddress);
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *coin,char *passphrase,char *wifstr)
|
|
{
|
|
//static uint32_t counter;
|
|
bits256 privkey,userpub,zero,userpass,checkkey,tmpkey; char str[65],str2[65],tmpstr[128]; cJSON *retjson; uint8_t tmptype,sig[128]; int32_t notarized,siglen; uint64_t nxtaddr;
|
|
uint8_t rmd160[20];
|
|
if ( (wifstr == 0 || wifstr[0] == 0) && LP_wifstr_valid(coin->symbol,passphrase) > 0 )
|
|
{
|
|
wifstr = passphrase;
|
|
passphrase = 0;
|
|
}
|
|
if ( passphrase != 0 && passphrase[0] != 0 )
|
|
{
|
|
if ( strlen(passphrase) == 66 && passphrase[0] == '0' && passphrase[1] == 'x' && is_hexstr(passphrase+2,0) == 64 )
|
|
{
|
|
decode_hex(privkey.bytes,32,passphrase+2);
|
|
//printf("ETH style privkey.(%s)\n",passphrase);
|
|
}
|
|
else
|
|
{
|
|
calc_NXTaddr(G.LP_NXTaddr,userpub.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
conv_NXTpassword(privkey.bytes,pubkeyp->bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
privkey.bytes[0] &= 248, privkey.bytes[31] &= 127, privkey.bytes[31] |= 64;
|
|
}
|
|
bitcoin_priv2wif(coin->symbol,coin->wiftaddr,tmpstr,privkey,coin->wiftype);
|
|
bitcoin_wif2priv(coin->symbol,coin->wiftaddr,&tmptype,&checkkey,tmpstr);
|
|
if ( bits256_cmp(privkey,checkkey) != 0 )
|
|
{
|
|
char str[65],str2[65]; printf("mismatched privkeys from wif conversion: %s -> %s -> %s\n",bits256_str(str,privkey),tmpstr,bits256_str(str2,checkkey));
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bitcoin_wif2priv(coin->symbol,coin->wiftaddr,&tmptype,&privkey,wifstr);
|
|
bitcoin_priv2wif(coin->symbol,coin->wiftaddr,tmpstr,privkey,tmptype);
|
|
if ( strcmp(tmpstr,wifstr) != 0 )
|
|
{
|
|
bitcoin_wif2priv(coin->symbol,coin->wiftaddr,&tmptype,&tmpkey,tmpstr);
|
|
if ( bits256_cmp(tmpkey,privkey) != 0 )
|
|
{
|
|
char str[65]; printf("%s error reproducing the wifstr, likely edge case like non-supported uncompressed pubkey privkey.%s\n",coin->symbol,bits256_str(str,privkey));
|
|
exit(1);
|
|
}
|
|
}
|
|
tmpkey = privkey;
|
|
nxtaddr = conv_NXTpassword(tmpkey.bytes,pubkeyp->bytes,0,0);
|
|
RS_encode(G.LP_NXTaddr,nxtaddr);
|
|
}
|
|
bitcoin_priv2pub(ctx,coin->symbol,coin->pubkey33,coin->smartaddr,privkey,coin->taddr,coin->pubtype);
|
|
#ifndef NOTETOMIC
|
|
if ( coin->etomic[0] != 0 )
|
|
{
|
|
uint8_t check64[64],checktype,checkrmd160[20]; char checkaddr[64],checkaddr2[64];
|
|
if ( LP_etomic_priv2pub(check64,privkey) == 0 )
|
|
{
|
|
if ( memcmp(check64,coin->pubkey33+1,32) == 0 )
|
|
{
|
|
if ( LP_etomic_priv2addr(checkaddr,privkey) == 0 && LP_etomic_pub2addr(checkaddr2,check64) == 0 && strcmp(checkaddr,checkaddr2) == 0 )
|
|
{
|
|
//printf("addr is (%s)\n",checkaddr);
|
|
strcpy(coin->smartaddr,checkaddr);
|
|
decode_hex(checkrmd160,20,checkaddr+2);
|
|
bitcoin_addr2rmd160(coin->symbol,coin->taddr,&checktype,rmd160,checkaddr);
|
|
if ( memcmp(rmd160,checkrmd160,20) != 0 )
|
|
printf("rmd160 doesnt match\n");
|
|
} else printf("error getting addr (%s) != (%s)\n",checkaddr,checkaddr2);
|
|
} else printf("pubkey 64 mismatch\n");
|
|
} else printf("error creating pubkey\n");
|
|
}
|
|
#endif
|
|
OS_randombytes(tmpkey.bytes,sizeof(tmpkey));
|
|
siglen = 0;
|
|
if ( bits256_nonz(privkey) == 0 || (siglen= bitcoin_sign(ctx,coin->symbol,sig,tmpkey,privkey,0)) <= 0 )
|
|
{
|
|
printf("illegal privkey %s\n",bits256_str(str,privkey));
|
|
exit(0);
|
|
}
|
|
if ( bits256_nonz(privkey) != 0 && bitcoin_verify(ctx,sig,siglen,tmpkey,coin->pubkey33,33) != 0 )
|
|
{
|
|
printf("signature.[%d] for %s by %s didnt verify\n",siglen,bits256_str(str,tmpkey),bits256_str(str2,privkey));
|
|
exit(0);
|
|
}
|
|
if ( coin->counter == 0 )
|
|
{
|
|
coin->counter++;
|
|
memcpy(G.LP_pubsecp,coin->pubkey33,33);
|
|
bitcoin_priv2wif(coin->symbol,coin->wiftaddr,tmpstr,privkey,coin->wiftype);
|
|
bitcoin_addr2rmd160(coin->symbol,coin->taddr,&tmptype,rmd160,coin->smartaddr);
|
|
LP_privkeyadd(privkey,rmd160);
|
|
G.LP_privkey = privkey;
|
|
if ( G.counter++ == 0 )
|
|
{
|
|
bitcoin_priv2wif(coin->symbol,coin->wiftaddr,G.USERPASS_WIFSTR,privkey,188);
|
|
bitcoin_wif2priv(coin->symbol,coin->wiftaddr,&tmptype,&checkkey,G.USERPASS_WIFSTR);
|
|
if ( bits256_cmp(checkkey,privkey) != 0 )
|
|
{
|
|
char str[65],str2[65];
|
|
printf("FATAL ERROR converting USERPASS_WIFSTR %s -> %s != %s\n",G.USERPASS_WIFSTR,bits256_str(str,checkkey),bits256_str(str2,privkey));
|
|
exit(-1);
|
|
}
|
|
conv_NXTpassword(userpass.bytes,pubkeyp->bytes,(uint8_t *)G.USERPASS_WIFSTR,(int32_t)strlen(G.USERPASS_WIFSTR));
|
|
userpub = curve25519(userpass,curve25519_basepoint9());
|
|
printf("userpass.(%s)\n",bits256_str(G.USERPASS,userpub));
|
|
}
|
|
}
|
|
if ( strcmp(coin->smartaddr,"RPZVpjptzfZnFZZoLnuSbfLexjtkhe6uvn") != 0 && coin->importedprivkey == 0 && coin->electrum == 0 && coin->userpass[0] != 0 && LP_getheight(¬arized,coin) > 0 )
|
|
{
|
|
memset(zero.bytes,0,sizeof(zero));
|
|
LP_listunspent_issue(coin->symbol,coin->smartaddr,0,zero,zero);
|
|
if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 )
|
|
{
|
|
if ( jobj(retjson,"error") != 0 )
|
|
{
|
|
printf("cant importprivkey.%s %s -> (%s), abort session\n",coin->symbol,coin->smartaddr,jprint(retjson,1));
|
|
exit(-1);
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
coin->importedprivkey = (uint32_t)time(NULL);
|
|
}
|
|
vcalc_sha256(0,checkkey.bytes,privkey.bytes,sizeof(privkey));
|
|
checkkey.bytes[0] &= 248, checkkey.bytes[31] &= 127, checkkey.bytes[31] |= 64;
|
|
G.LP_mypub25519 = *pubkeyp = curve25519(checkkey,curve25519_basepoint9());
|
|
G.LP_mypriv25519 = checkkey;
|
|
LP_pubkeyadd(G.LP_mypub25519);
|
|
return(privkey);
|
|
}
|
|
|
|
void verus_utxos(struct iguana_info *coin,char *coinaddr)
|
|
{
|
|
cJSON *array,*item; char buf[64],str[65]; int32_t i,m,vout,n=0; bits256 txid;
|
|
sprintf(buf,"[%d, 99999999, [\"%s\"]]",1,coinaddr);
|
|
array = bitcoin_json(coin,"listunspent",buf);
|
|
if ( array != 0 )
|
|
{
|
|
if ( (n= cJSON_GetArraySize(array)) > 0 )
|
|
{
|
|
for (i=m=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if ( fabs(jdouble(item,"amount") - 64.) < 0.00011 )
|
|
{
|
|
txid = jbits256(item,"txid");
|
|
vout = jint(item,"vout");
|
|
printf("%d: %s/v%d\n",m,bits256_str(str,txid),vout);
|
|
m++;
|
|
}
|
|
}
|
|
}
|
|
free_json(array);
|
|
}
|
|
printf("scanned %d utxos m.%d\n",n,m);
|
|
}
|
|
|
|
char *verusblocks()
|
|
{
|
|
bits256 hash,txid; uint8_t script[44]; double value,avestakedsize,stakedval,RTu3sum,powsum,supply,possum,histo[1280],myhisto[1280]; int32_t num10,num17,num20,num16,num23000,numpow,numpos,num,locked,height,i,m,n,z,gotblock,numstaked,posflag,npos,npow; char hashstr[64],firstaddr[64],stakingaddr[64],*addr0,*lastaddr,*hexstr; cJSON *blockjson,*txobj,*vouts,*vout,*vout1,*sobj,*addresses,*txs;
|
|
struct iguana_info *coin = LP_coinfind("VRSC");
|
|
if ( coin == 0 )
|
|
return(clonestr("{\"error\":\"VRSC not active\"}"));
|
|
char *coinaddr = "RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj";
|
|
if ( strcmp(coinaddr,coin->smartaddr) != 0 )
|
|
return(clonestr("{\"error\":\"mismatched smartaddr\"}"));
|
|
//verus_utxos(coin,coin->smartaddr);
|
|
hash = LP_getbestblockhash(coin);
|
|
memset(histo,0,sizeof(histo));
|
|
memset(myhisto,0,sizeof(myhisto));
|
|
num23000 = num16 = num17 = num10 = num20 = numstaked = 0;
|
|
avestakedsize = possum = powsum = supply = RTu3sum = 0.;
|
|
numpow = numpos = num = npos = npow = 0;
|
|
if ( bits256_nonz(hash) != 0 )
|
|
{
|
|
bits256_str(hashstr,hash);
|
|
height = -1;
|
|
while ( (blockjson= LP_blockjson(&height,coin->symbol,hashstr,0)) != 0 )
|
|
{
|
|
num++;
|
|
stakedval = 0.;
|
|
height = juint(blockjson,"height");
|
|
if ( (txs= jarray(&n,blockjson,"tx")) != 0 )
|
|
{
|
|
txid = jbits256i(txs,0);
|
|
value = 0;
|
|
posflag = 0;
|
|
locked = 0;
|
|
gotblock = 0;
|
|
lastaddr = addr0 = "";
|
|
memset(script,0,sizeof(script));
|
|
memset(firstaddr,0,sizeof(firstaddr));
|
|
memset(stakingaddr,0,sizeof(stakingaddr));
|
|
if ( (txobj= LP_gettx("verus",coin->symbol,txid,0)) != 0 )
|
|
{
|
|
//printf("TX.(%s)\n",jprint(txobj,0));
|
|
if ( (vouts= jarray(&m,txobj,"vout")) != 0 )
|
|
{
|
|
if ( (vout= jitem(vouts,0)) != 0 )
|
|
{
|
|
value = jdouble(vout,"value");
|
|
supply += value;
|
|
hexstr = 0;
|
|
if ( (sobj= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 )
|
|
{
|
|
if ( strcmp(hexstr,"2102ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92ac") == 0 || strcmp(hexstr,"2102aef0f54a967031f4c63b36d12741fbb9ca39713baedfff7f8c0d0d8ee14ee0ebac") == 0 || strcmp(hexstr,"76a914cc39e9e699f86b03a5cf1d7f2a0b411cf652641788ac") == 0 || strcmp(hexstr,"76a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688ac") == 0 )
|
|
{
|
|
gotblock = 1;
|
|
}
|
|
}
|
|
if ( m == 2 && (vout1= jitem(vouts,1)) != 0 )
|
|
{
|
|
// 6a2001039bbc0bb17576a9149a3af738444dd86b55c86752247aec2e7deb842688ac
|
|
if ( jdouble(vout1,"value") == 0. && (sobj= jobj(vout1,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && strlen(hexstr) <= 88 )
|
|
{
|
|
if ( strlen(hexstr) == 68 )
|
|
{
|
|
decode_hex(script,34,hexstr);
|
|
bitcoin_address(coin->symbol,firstaddr,coin->taddr,coin->pubtype,&script[12],20);
|
|
//printf("%s\n",&hexstr[24]);
|
|
}
|
|
else
|
|
{
|
|
decode_hex(script,44,hexstr);
|
|
bitcoin_address(coin->symbol,firstaddr,coin->taddr,coin->pubtype,&script[10],33);
|
|
}
|
|
locked = ((int32_t)script[6] << 16) + ((int32_t)script[5] << 8) + script[4];
|
|
addr0 = firstaddr;
|
|
} else printf("unexpected vout1.(%s) (%s).%d %.8f\n",jprint(vout1,0),hexstr!=0?hexstr:"",(int32_t)strlen(hexstr),jdouble(vout1,"value"));
|
|
} //else printf("coinbase without opret (%s)\n",jprint(vouts,0));
|
|
}
|
|
}
|
|
free_json(txobj);
|
|
}
|
|
if ( n > 1 && (txobj= LP_gettx("verus",coin->symbol,jbits256i(txs,n-1),0)) != 0 )
|
|
{
|
|
if ( (vouts= jarray(&m,txobj,"vout")) != 0 )
|
|
{
|
|
if ( (vout= jitem(vouts,0)) != 0 && m == 1 )
|
|
{
|
|
if ( (sobj= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&z,sobj,"addresses")) != 0 )
|
|
{
|
|
lastaddr = jstri(addresses,0);
|
|
if ( lastaddr == 0 )
|
|
lastaddr = "";
|
|
else
|
|
{
|
|
strcpy(stakingaddr,lastaddr);
|
|
stakedval = jdouble(vout,"value");
|
|
avestakedsize += stakedval;
|
|
numstaked++;
|
|
//printf("stakedval %f\n",stakedval);
|
|
posflag = 1;
|
|
//printf("ht.%d found staking address.(%s) %.8f (%s)\n",height,stakingaddr,stakedval,jprint(vout,0));
|
|
}
|
|
} else printf("no addresses[0] in (%s) %s\n",jprint(vout,0),sobj!=0?jprint(sobj,0):"");
|
|
} //else printf("n.%d m.%d no first out in lastvout.(%s)\n",n,m,jprint(txobj,0));
|
|
} // else printf("cant find vout.(%s)\n",jprint(txobj,0));
|
|
free_json(txobj);
|
|
}
|
|
if ( posflag != 0 )
|
|
{
|
|
numpos++;
|
|
if ( strcmp(coinaddr,stakingaddr) == 0 || strcmp("RTu3JZZKLJTcfNwBa19dWRagEfQq49STqC",stakingaddr) == 0 )
|
|
{
|
|
if (strcmp("RTu3JZZKLJTcfNwBa19dWRagEfQq49STqC",stakingaddr) == 0 )
|
|
RTu3sum += value;
|
|
possum += value, npos++;
|
|
if ( num < 1500 )
|
|
printf("ht.%-5d lock.%-7d PoS cb.(%s) stake.(%s) %.8f %.8f\n",height,locked,addr0,stakingaddr,value,stakedval);
|
|
if ( height > 23000 )
|
|
{
|
|
char strbuf[64];
|
|
sprintf(strbuf,"%.0f",stakedval);
|
|
if ( strcmp(strbuf,"20") == 0 )
|
|
num20++;
|
|
else if ( strcmp(strbuf,"17") == 0 )
|
|
num17++;
|
|
else if ( strcmp(strbuf,"16") == 0 )
|
|
num16++;
|
|
else if ( strcmp(strbuf,"10") == 0 )
|
|
num10++;
|
|
else printf("got strbuf.(%s)\n",strbuf);
|
|
}
|
|
}
|
|
else if ( 0 && num < 100 )
|
|
printf("ht.%-5d lock.%-7d PoS cb.(%s) stake.(%s) %.8f %.8f\n",height,locked,addr0,stakingaddr,value,stakedval);
|
|
}
|
|
else
|
|
{
|
|
numpow++;
|
|
if ( num < 100 && strcmp(coinaddr,addr0) == 0 )
|
|
printf("ht.%-5d lock.%-7d PoW coinbase.(%s) %.8f\n",height,locked,addr0,value);
|
|
if ( strcmp(coinaddr,addr0) == 0 || gotblock != 0 )
|
|
powsum += value, npow++;
|
|
}
|
|
histo[locked/1000] += value;
|
|
if ( strcmp(coinaddr,addr0) == 0 || strcmp("RTu3JZZKLJTcfNwBa19dWRagEfQq49STqC",addr0) == 0 )
|
|
myhisto[locked/1000] += value;
|
|
}
|
|
bits256_str(hashstr,jbits256(blockjson,"previousblockhash"));
|
|
free_json(blockjson);
|
|
if ( height == 5040 )
|
|
break;
|
|
else if ( height == 23000 )
|
|
{
|
|
num23000 = num;
|
|
printf("num10.%d num16.%d num17.%d num20.%d / num23000.%d -> %.2f%% %.2f%% %.2f%% %.2f%% [%.3f %.3f %.3f %.3f] %.3f ave %.8f\n",num10,num16,num17,num20,num23000,100.*(double)num10/num23000,100.*(double)num16/num23000,100.*(double)num17/num23000,100.*(double)num20/num23000,(100.*(double)num10/num23000)/2.87,(100.*(double)num16/num23000)/10.5,(100.*(double)num17/num23000)/4.88,(100.*(double)num20/num23000)/5.74,(100.*(double)(num10+num16+num17+num20)/num23000)/24,avestakedsize/numstaked);
|
|
}
|
|
else if ( (num % 1000) == 0 || (num < 1000 && (num % 100) == 0) )
|
|
{
|
|
printf("num.%d PoW %.2f%% %.0f %d v %d PoS %.2f%% %.0f -> %.0f supply %.0f PoW %.1f%% PoS %.1f%% both %.1f%% RTu3 %.8f %.1f%%\n",num,100.*(double)numpow/num,powsum,npow,npos,100.*(double)numpos/num,possum,powsum+possum,supply,100.*powsum/supply,100.*possum/supply,100.*(powsum+possum)/supply,RTu3sum,100.*RTu3sum/supply);
|
|
}
|
|
}
|
|
}
|
|
if ( num > 0 )
|
|
{
|
|
if ( 0 )
|
|
{
|
|
for (i=0; i<sizeof(histo)/sizeof(*histo); i++)
|
|
if ( histo[i] != 0 )
|
|
printf("%d %.8f, ",i*1000,histo[i]);
|
|
printf("timelocked\n");
|
|
for (i=0; i<sizeof(myhisto)/sizeof(*myhisto); i++)
|
|
if ( myhisto[i] != 0 )
|
|
printf("%d %.8f, ",i*1000,myhisto[i]);
|
|
printf("mytimelocked\n");
|
|
}
|
|
printf("num.%d PoW %.2f%% %.8f %d v %d PoS %.2f%% %.8f -> %.8f supply %.8f PoW %.1f%% PoS %.1f%% both %.1f%% RTu3sum %.8f %.1f%%\n",num,100.*(double)numpow/num,powsum,npow,npos,100.*(double)numpos/num,possum,powsum+possum,supply,100.*powsum/supply,100.*possum/supply,100.*(powsum+possum)/supply,RTu3sum,100.*RTu3sum/supply);
|
|
printf("num10.%d num16.%d num17.%d num20.%d / num23000.%d -> %.2f%% %.2f%% %.2f%% %.2f%% [%.3f %.3f %.3f %.3f] %.3f ave %.8f\n",num10,num16,num17,num20,num23000,100.*(double)num10/num23000,100.*(double)num16/num23000,100.*(double)num17/num23000,100.*(double)num20/num23000,(100.*(double)num10/num23000)/2.87,(100.*(double)num16/num23000)/10.5,(100.*(double)num17/num23000)/4.88,(100.*(double)num20/num23000)/5.74,(100.*(double)(num10+num16+num17+num20)/num23000)/24,avestakedsize/numstaked);
|
|
}
|
|
return(clonestr("{\"result\":\"success\"}"));
|
|
}
|
|
|
|
void LP_privkey_updates(void *ctx,int32_t pubsock,char *passphrase)
|
|
{
|
|
struct iguana_info *coin,*tmp; bits256 pubkey,privkey; uint8_t pubkey33[33]; int32_t initonly;
|
|
initonly = (passphrase != 0);
|
|
memset(privkey.bytes,0,sizeof(privkey));
|
|
memset(pubkey.bytes,0,sizeof(pubkey));
|
|
//printf("Total coins: %d\n", HASH_COUNT(LP_coins));
|
|
//int num_iter = 0;
|
|
HASH_ITER(hh,LP_coins,coin,tmp)
|
|
{
|
|
//printf("LP_privkey_updates [%02d / %02d]\n", num_iter++, HASH_COUNT(LP_coins));
|
|
if ( initonly != 0 )
|
|
{
|
|
coin->counter = 0;
|
|
memset(coin->smartaddr,0,sizeof(coin->smartaddr));
|
|
if ( bits256_nonz(privkey) == 0 || coin->smartaddr[0] == 0 )
|
|
{
|
|
privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,coin,passphrase,"");
|
|
}
|
|
}
|
|
//printf("i.%d of %d\n",i,LP_numcoins);
|
|
else if ( IAMLP == 0 || coin->inactive == 0 )
|
|
{
|
|
//printf("from updates %s\n",coin->symbol);
|
|
if ( 0 && LP_privkey_init(pubsock,coin,G.LP_privkey,G.LP_mypub25519) == 0 && (LP_rand() % 10) == 0 )
|
|
{
|
|
//LP_postutxos(coin->symbol,coin->smartaddr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32_t LP_passphrase_init(char *passphrase,char *gui,uint16_t netid,char *seednode)
|
|
{
|
|
static void *ctx; struct iguana_info *coin,*tmp; int32_t counter;
|
|
uint8_t pubkey33[100];
|
|
if ( ctx == 0 )
|
|
ctx = bitcoin_ctx();
|
|
if ( G.LP_pendingswaps != 0 )
|
|
return(-1);
|
|
if ( netid != G.netid )
|
|
{
|
|
if ( IAMLP != 0 )
|
|
{
|
|
printf("sorry, LP nodes can only set netid during startup\n");
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
printf(">>>>>>>>>>>>> netid.%d vs G.netid %d\n",netid,G.netid);
|
|
LP_closepeers();
|
|
LP_initpeers(LP_mypubsock,LP_mypeer,LP_myipaddr,RPC_port,netid,seednode);
|
|
}
|
|
}
|
|
G.initializing = 1;
|
|
if ( gui == 0 )
|
|
gui = "cli";
|
|
counter = G.USERPASS_COUNTER;
|
|
HASH_ITER(hh,LP_coins,coin,tmp)
|
|
{
|
|
coin->importedprivkey = 0;
|
|
}
|
|
while ( G.waiting == 0 )
|
|
{
|
|
printf("waiting for G.waiting\n");
|
|
sleep(5);
|
|
}
|
|
memset(&G,0,sizeof(G));
|
|
G.netid = netid;
|
|
safecopy(G.seednode,seednode,sizeof(G.seednode));
|
|
|
|
vcalc_sha256(0,G.LP_passhash.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
LP_privkey_updates(ctx,LP_mypubsock,passphrase);
|
|
bitcoin_pubkey33(ctx, pubkey33, G.LP_privkey);
|
|
calc_rmd160_sha256(G.LP_myrmd160, pubkey33, 33);
|
|
init_hexbytes_noT(G.LP_myrmd160str,G.LP_myrmd160,20);
|
|
G.LP_sessionid = (uint32_t)time(NULL);
|
|
safecopy(G.gui,gui,sizeof(G.gui));
|
|
LP_tradebot_pauseall();
|
|
LP_portfolio_reset();
|
|
LP_priceinfos_clear();
|
|
G.USERPASS_COUNTER = counter;
|
|
G.initializing = 0;
|
|
//LP_cmdchannels();
|
|
return(0);
|
|
}
|
|
|
|
void LP_privkey_tests()
|
|
{
|
|
char wifstr[64],str[65],str2[65]; bits256 privkey,checkkey; int32_t i; uint8_t tmptype;
|
|
for (i=0; i<200000000; i++)
|
|
{
|
|
privkey = rand256(0);
|
|
bitcoin_priv2wif("KMD",0,wifstr,privkey,0xff);
|
|
bitcoin_wif2priv("KMD",0,&tmptype,&checkkey,wifstr);
|
|
if ( bits256_cmp(privkey,checkkey) != 0 )
|
|
{
|
|
printf("i.%d: %s vs %s\n",i,bits256_str(str,privkey),bits256_str(str2,checkkey));
|
|
exit(-1);
|
|
}
|
|
if ( (i % 1000000) == 0 )
|
|
fprintf(stderr,"%.1f%% ",100.*(double)i/200000000);
|
|
}
|
|
printf("%d privkeys checked\n",i);
|
|
}
|
|
|
|
|
|
#define JPG_ENCRYPTED_MAXSIZE 32768
|
|
|
|
int32_t JPG_encrypt(uint16_t ind,uint8_t encoded[JPG_ENCRYPTED_MAXSIZE],uint8_t *msg,int32_t msglen,bits256 privkey)
|
|
{
|
|
bits256 pubkey; int32_t len = 2; uint8_t space[JPG_ENCRYPTED_MAXSIZE],*nonce,*cipher;
|
|
pubkey = acct777_pubkey(privkey);
|
|
encoded[len++] = ind & 0xff;
|
|
encoded[len++] = (ind >> 8) & 0xff;
|
|
nonce = &encoded[len];
|
|
OS_randombytes(nonce,crypto_box_NONCEBYTES);
|
|
cipher = &encoded[len + crypto_box_NONCEBYTES];
|
|
msglen = _SuperNET_cipher(nonce,&encoded[len + crypto_box_NONCEBYTES],msg,msglen,pubkey,privkey,space);
|
|
msglen += crypto_box_NONCEBYTES;
|
|
msg = encoded;
|
|
msglen += len;
|
|
encoded[0] = msglen & 0xff;
|
|
encoded[1] = (msglen >> 8) & 0xff;
|
|
int32_t i; for (i=0; i<msglen; i++)
|
|
printf("%02x",encoded[i]);
|
|
printf(" encoded.%d\n",msglen);
|
|
return(msglen);
|
|
}
|
|
|
|
uint8_t *JPG_decrypt(uint16_t *indp,int32_t *recvlenp,uint8_t space[JPG_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES],uint8_t *encoded,bits256 privkey)
|
|
{
|
|
bits256 pubkey; uint8_t *extracted=0,*nonce,*cipher; uint16_t msglen,ind; int32_t cipherlen,len = 4;
|
|
*recvlenp = 0;
|
|
*indp = -1;
|
|
pubkey = acct777_pubkey(privkey);
|
|
msglen = ((int32_t)encoded[1] << 8) | encoded[0];
|
|
ind = ((int32_t)encoded[3] << 8) | encoded[2];
|
|
nonce = &encoded[len];
|
|
cipher = &encoded[len + crypto_box_NONCEBYTES];
|
|
cipherlen = msglen - (len + crypto_box_NONCEBYTES);
|
|
if ( cipherlen > 0 && cipherlen <= JPG_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES )
|
|
{
|
|
//int32_t i; for (i=0; i<cipherlen; i++)
|
|
// printf("%02x",cipher[i]);
|
|
//printf(" cipherlen\n");
|
|
if ( (extracted= _SuperNET_decipher(nonce,cipher,space,cipherlen,pubkey,privkey)) != 0 )
|
|
{
|
|
//int32_t i; for (i=0; i<msglen; i++)
|
|
// printf("%02x",encoded[i]);
|
|
//printf(" restored\n");
|
|
msglen = (cipherlen - crypto_box_ZEROBYTES);
|
|
*recvlenp = msglen;
|
|
*indp = ind;
|
|
}
|
|
} //else printf("cipher.%d too big for %d\n",cipherlen,JPG_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES);
|
|
return(extracted);
|
|
}
|
|
|
|
int32_t LP_opreturn_decrypt(uint16_t *ind16p,uint8_t *decoded,uint8_t *encoded,int32_t encodedlen,char *passphrase)
|
|
{
|
|
bits256 privkey; int32_t msglen; uint8_t *extracted,space[JPG_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES];
|
|
if ( passphrase != 0 && passphrase[0] != 0 )
|
|
{
|
|
vcalc_sha256(0,privkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
msglen = ((int32_t)encoded[1] << 8) | encoded[0];
|
|
*ind16p = ((int32_t)encoded[3] << 8) | encoded[2];
|
|
if ( msglen == encodedlen && (extracted= JPG_decrypt(ind16p,&msglen,space,encoded,privkey)) != 0 )
|
|
{
|
|
memcpy(decoded,extracted,msglen);
|
|
return(msglen);
|
|
} else return(-1);
|
|
}
|
|
else
|
|
{
|
|
*ind16p = calc_crc32(0,extracted,encodedlen);
|
|
memcpy(decoded,extracted,encodedlen);
|
|
return(encodedlen);
|
|
}
|
|
}
|
|
|
|
int32_t LP_opreturn_encrypt(uint8_t *dest,int32_t maxsize,uint8_t *data,int32_t datalen,char *passphrase,uint16_t ind16)
|
|
{
|
|
bits256 privkey; int32_t len; uint8_t encoded[JPG_ENCRYPTED_MAXSIZE];
|
|
vcalc_sha256(0,privkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
|
|
if ( (len= JPG_encrypt(ind16,encoded,data,datalen,privkey)) > 0 )
|
|
{
|
|
//printf("datalen.%d -> len.%d max.%d\n",datalen,len,maxsize);
|
|
if ( len <= maxsize )
|
|
{
|
|
memcpy(dest,encoded,len);
|
|
return(len);
|
|
}
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
// from https://github.com/owencm/C-Steganography-Framework
|
|
#include "../../crypto777/jpeg/cdjpeg.h" // Common decls for compressing and decompressing jpegs
|
|
|
|
int32_t LP_jpg_process(int32_t *capacityp,char *inputfname,char *outputfname,uint8_t *decoded,uint8_t *origdata,int32_t origrequired,int32_t power2,char *password,uint16_t *indp)
|
|
{
|
|
struct jpeg_decompress_struct inputinfo;
|
|
struct jpeg_compress_struct outputinfo;
|
|
struct jpeg_error_mgr jerr;
|
|
jvirt_barray_ptr *coef_arrays;
|
|
JDIMENSION i,compnum,rownum,blocknum;
|
|
JBLOCKARRAY coef_buffers[MAX_COMPONENTS];
|
|
JBLOCKARRAY row_ptrs[MAX_COMPONENTS];
|
|
bits256 privkey; FILE *input_file,*output_file; int32_t recvlen,msglen,val,modified,emit,totalrows,limit,required; uint16_t checkind; uint8_t *decrypted,*space,*data=0;
|
|
if ((input_file = fopen(inputfname, READ_BINARY)) == NULL)
|
|
{
|
|
fprintf(stderr, "Can't open %s\n", inputfname);
|
|
//exit(EXIT_FAILURE);
|
|
return(-1);
|
|
}
|
|
required = origrequired;
|
|
memset(privkey.bytes,0,sizeof(privkey));
|
|
if ( password != 0 && password[0] != 0 )
|
|
{
|
|
if ( required/8 > JPG_ENCRYPTED_MAXSIZE-60 )
|
|
return(-1);
|
|
data = calloc(1,required/8+512);
|
|
vcalc_sha256(0,privkey.bytes,(uint8_t *)password,(int32_t)strlen(password));
|
|
if ( origdata != 0 )
|
|
{
|
|
msglen = JPG_encrypt(*indp,data,origdata,required/8,privkey);
|
|
required = msglen * 8;
|
|
{
|
|
space = calloc(1,JPG_ENCRYPTED_MAXSIZE);
|
|
if ( (decrypted= JPG_decrypt(&checkind,&recvlen,space,data,privkey)) == 0 || recvlen != origrequired/8 || checkind != *indp || memcmp(decrypted,origdata,origrequired/8) != 0 )
|
|
printf("A decryption error: checkind.%d vs %d, recvlen.%d vs %d, decrypted.%p\n",checkind,*indp,recvlen,origrequired/8,decrypted);
|
|
else
|
|
{
|
|
for (i=0; i<recvlen; i++)
|
|
printf("%02x",decrypted[i]);
|
|
printf(" VERIFIED decryption.%d ind.%d msglen.%d required.%d\n",recvlen,*indp,msglen,required);
|
|
}
|
|
free(space);
|
|
}
|
|
} else required += 60 * 8;
|
|
} else data = origdata;
|
|
if ( power2 < 0 || power2 > 30 )
|
|
power2 = 7;
|
|
limit = 1;
|
|
while ( power2 > 0 )
|
|
{
|
|
limit <<= 1;
|
|
power2--;
|
|
}
|
|
// Initialize the JPEG compression and decompression objects with default error handling
|
|
inputinfo.err = jpeg_std_error(&jerr);
|
|
jpeg_create_decompress(&inputinfo);
|
|
// Specify data source for decompression and recompression
|
|
jpeg_stdio_src(&inputinfo, input_file);
|
|
(void) jpeg_read_header(&inputinfo, TRUE);
|
|
for (compnum=0; compnum<inputinfo.num_components; compnum++)
|
|
coef_buffers[compnum] = ((&inputinfo)->mem->alloc_barray)((j_common_ptr)&inputinfo,JPOOL_IMAGE,inputinfo.comp_info[compnum].width_in_blocks,inputinfo.comp_info[compnum].height_in_blocks);
|
|
coef_arrays = jpeg_read_coefficients(&inputinfo);
|
|
// Copy DCT coeffs to a new array
|
|
int num_components = inputinfo.num_components;
|
|
size_t *block_row_size;//[num_components];
|
|
int *width_in_blocks;//[num_components];
|
|
int *height_in_blocks;//[num_components];
|
|
block_row_size = calloc(sizeof(*block_row_size),num_components);
|
|
width_in_blocks = calloc(sizeof(*width_in_blocks),num_components);
|
|
height_in_blocks = calloc(sizeof(*height_in_blocks),num_components);
|
|
*capacityp = modified = emit = totalrows = 0;
|
|
if ( decoded != 0 )
|
|
memset(decoded,0,required/8+1);
|
|
for (compnum=0; compnum<num_components; compnum++)
|
|
{
|
|
height_in_blocks[compnum] = inputinfo.comp_info[compnum].height_in_blocks;
|
|
width_in_blocks[compnum] = inputinfo.comp_info[compnum].width_in_blocks;
|
|
block_row_size[compnum] = (size_t) SIZEOF(JCOEF)*DCTSIZE2*width_in_blocks[compnum];
|
|
for (rownum=0; rownum<height_in_blocks[compnum]; rownum++)
|
|
{
|
|
row_ptrs[compnum] = ((&inputinfo)->mem->access_virt_barray)((j_common_ptr)&inputinfo,coef_arrays[compnum],rownum,(JDIMENSION)1,FALSE);
|
|
for (blocknum=0; blocknum<width_in_blocks[compnum]; blocknum++)
|
|
{
|
|
for (i=0; i<DCTSIZE2; i++)
|
|
{
|
|
val = row_ptrs[compnum][0][blocknum][i];
|
|
if ( val < -limit || val >= limit )
|
|
{
|
|
if ( (*capacityp) < required )
|
|
{
|
|
if ( (val & 1) != 0 )
|
|
SETBIT(decoded,(*capacityp));
|
|
//printf("%c",(val&1)!=0?'1':'0');
|
|
}
|
|
(*capacityp)++;
|
|
}
|
|
coef_buffers[compnum][rownum][blocknum][i] = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( password != 0 && password[0] != 0 )
|
|
{
|
|
space = calloc(1,JPG_ENCRYPTED_MAXSIZE);
|
|
if ( (decrypted= JPG_decrypt(indp,&recvlen,space,decoded,privkey)) != 0 && recvlen == origrequired/8 )
|
|
{
|
|
for (i=0; i<recvlen; i++)
|
|
{
|
|
//printf("%02x",decrypted[i]);
|
|
decoded[i] = decrypted[i];
|
|
}
|
|
//printf(" decrypted.%d ind.%d\n",recvlen,*indp);
|
|
}
|
|
free(space);
|
|
}
|
|
//printf(" capacity %d required.%d power2.%d limit.%d\n",*capacityp,required,power2,limit);
|
|
if ( *capacityp > required && outputfname != 0 && outputfname[0] != 0 )
|
|
{
|
|
if ((output_file = fopen(outputfname, WRITE_BINARY)) == NULL) {
|
|
fprintf(stderr, "Can't open %s\n", outputfname);
|
|
if ( data != origdata )
|
|
free(data);
|
|
return(-1);
|
|
}
|
|
outputinfo.err = jpeg_std_error(&jerr);
|
|
jpeg_create_compress(&outputinfo);
|
|
jpeg_stdio_dest(&outputinfo, output_file);
|
|
jpeg_copy_critical_parameters(&inputinfo,&outputinfo);
|
|
// Print out or modify DCT coefficients
|
|
for (compnum=0; compnum<num_components; compnum++)
|
|
{
|
|
for (rownum=0; rownum<height_in_blocks[compnum]; rownum++)
|
|
{
|
|
for (blocknum=0; blocknum<width_in_blocks[compnum]; blocknum++)
|
|
{
|
|
//printf("\n\nComponent: %i, Row:%i, Column: %i\n", compnum, rownum, blocknum);
|
|
for (i=0; i<DCTSIZE2&&emit<required; i++)
|
|
{
|
|
val = coef_buffers[compnum][rownum][blocknum][i];
|
|
if ( val < -limit || val >= limit )
|
|
{
|
|
val &= ~1;
|
|
if (GETBIT(data,emit) != 0 )//|| (emit >= required && (rand() & 1) != 0) )
|
|
val |= 1;
|
|
//printf("%c",(val&1)!=0?'1':'0');
|
|
coef_buffers[compnum][rownum][blocknum][i] = val;
|
|
emit++;
|
|
}
|
|
//printf("%i,", coef_buffers[compnum][rownum][blocknum][i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//printf(" emit.%d\n",emit);
|
|
// Output the new DCT coeffs to a JPEG file
|
|
modified = 0;
|
|
for (compnum=0; compnum<num_components; compnum++)
|
|
{
|
|
for (rownum=0; rownum<height_in_blocks[compnum]; rownum++)
|
|
{
|
|
row_ptrs[compnum] = ((&outputinfo)->mem->access_virt_barray)((j_common_ptr)&outputinfo,coef_arrays[compnum],rownum,(JDIMENSION)1,TRUE);
|
|
if ( memcmp(row_ptrs[compnum][0][0],coef_buffers[compnum][rownum][0],block_row_size[compnum]) != 0 )
|
|
{
|
|
memcpy(row_ptrs[compnum][0][0],coef_buffers[compnum][rownum][0],block_row_size[compnum]);
|
|
modified++;
|
|
}
|
|
totalrows++;
|
|
}
|
|
}
|
|
// Write to the output file
|
|
jpeg_write_coefficients(&outputinfo, coef_arrays);
|
|
// Finish compression and release memory
|
|
jpeg_finish_compress(&outputinfo);
|
|
jpeg_destroy_compress(&outputinfo);
|
|
fclose(output_file);
|
|
}
|
|
jpeg_finish_decompress(&inputinfo);
|
|
jpeg_destroy_decompress(&inputinfo);
|
|
fclose(input_file);
|
|
if ( modified != 0 )
|
|
{
|
|
printf("New DCT coefficients successfully written to %s, capacity %d modifiedrows.%d/%d emit.%d\n",outputfname,*capacityp,modified,totalrows,emit);
|
|
}
|
|
free(block_row_size);
|
|
free(width_in_blocks);
|
|
free(height_in_blocks);
|
|
if ( data != origdata )
|
|
free(data);
|
|
return(modified);
|
|
}
|
|
|
|
char *LP_jpg(char *srcfile,char *destfile,int32_t power2,char *passphrase,char *datastr,int32_t required,uint16_t ind)
|
|
{
|
|
cJSON *retjson; int32_t len=0,modified,capacity; char *decodedstr; uint8_t *data=0,*decoded=0;
|
|
if ( srcfile != 0 && srcfile[0] != 0 )
|
|
{
|
|
retjson = cJSON_CreateObject();
|
|
if ( datastr != 0 && datastr[0] != 0 )
|
|
{
|
|
if ( (len= is_hexstr(datastr,0)) > 0 )
|
|
{
|
|
len >>= 1;
|
|
data = calloc(1,len);
|
|
decode_hex(data,len,datastr);
|
|
required = len * 8;
|
|
//int32_t i; for (i=0; i<required; i++)
|
|
// printf("%c",'0'+(GETBIT(data,i)!=0));
|
|
//printf(" datastr.%d %s\n",required,datastr);
|
|
}
|
|
}
|
|
if ( required > 0 )
|
|
decoded = calloc(1,len+required);
|
|
if ( (modified= LP_jpg_process(&capacity,srcfile,destfile,decoded,data,required,power2,passphrase,&ind)) < 0 )
|
|
jaddstr(retjson,"error","file not found");
|
|
else
|
|
{
|
|
jaddstr(retjson,"result","success");
|
|
jaddnum(retjson,"modifiedrows",modified);
|
|
if ( modified != 0 )
|
|
jaddstr(retjson,"outputfile",destfile);
|
|
jaddnum(retjson,"power2",power2);
|
|
jaddnum(retjson,"capacity",capacity);
|
|
jaddnum(retjson,"required",required);
|
|
jaddnum(retjson,"ind",ind);
|
|
}
|
|
if ( decoded != 0 )
|
|
{
|
|
if ( capacity > 0 )
|
|
{
|
|
//printf("len.%d required.%d capacity.%d\n",len,required,capacity);
|
|
decodedstr = calloc(1,(len+required)*2+1);
|
|
init_hexbytes_noT(decodedstr,decoded,required/8);
|
|
jaddstr(retjson,"decoded",decodedstr);
|
|
free(decodedstr);
|
|
}
|
|
free(decoded);
|
|
}
|
|
if ( data != 0 )
|
|
free(data);
|
|
return(jprint(retjson,1));
|
|
} else return(clonestr("{\"error\":\"no source file error\"}"));
|
|
}
|
|
|
|
|
|
|
|
|
|
|