From d6d7229eb27adeac0470de8fa38fd8239476b2d4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 Feb 2016 12:12:11 -0300 Subject: [PATCH] test --- crypto777/OS_portable.h | 1 + crypto777/libgfshare.c | 164 ++++++-- deprecated/obsolete.h | 19 + iguana/SuperNET.h | 3 + iguana/exchanges/bitcoin.c | 23 +- iguana/exchanges777.h | 4 +- iguana/iguana777.h | 1 + iguana/iguana_chains.c | 7 +- iguana/iguana_instantdex.c | 20 +- iguana/iguana_peers.c | 2 +- iguana/iguana_pubkeys.c | 2 +- iguana/main.c | 757 +++++++++++++++++++++++++++++++++- iguana/swaps/iguana_BTCswap.c | 442 +++++++++++++++----- 13 files changed, 1279 insertions(+), 166 deletions(-) diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index 7bbb0621d..322caa2d3 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -355,6 +355,7 @@ bits256 bits256_lshift(bits256 x); bits256 bits256_from_compact(uint32_t c); bits256 bits256_conv(char *hexstr); int32_t btc_priv2pub(uint8_t pubkey[33],uint8_t privkey[32]); +void calc_shares(unsigned char *shares,unsigned char *secret,int32_t size,int32_t width,int32_t M,int32_t N,unsigned char *sharenrs); extern char *Iguana_validcommands[]; extern bits256 GENESIS_PUBKEY,GENESIS_PRIVKEY; diff --git a/crypto777/libgfshare.c b/crypto777/libgfshare.c index 4f2ea6df3..393e6d963 100755 --- a/crypto777/libgfshare.c +++ b/crypto777/libgfshare.c @@ -39,10 +39,10 @@ struct _gfshare_ctx { uint32_t sharecount,threshold,size,buffersize; - unsigned char sharenrs[255],buffer[]; + uint8_t sharenrs[255],buffer[]; }; -unsigned char ctx_logs[256] = { +uint8_t ctx_logs[256] = { 0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, @@ -76,7 +76,7 @@ unsigned char ctx_logs[256] = { 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf }; -unsigned char ctx_exps[510] = { +uint8_t ctx_exps[510] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, @@ -142,20 +142,20 @@ unsigned char ctx_exps[510] = { 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e }; -/*void _gfshare_fill_rand_using_random(unsigned char *buffer,unsigned long long count) +/*void _gfshare_fill_rand_using_random(uint8_t *buffer,unsigned long long count) { uint32_t i; for (i=0; i> 8; // apparently the bottom 8 aren't very random but the middles ones are }*/ -//void randombytes(unsigned char *x,long xlen); +//void randombytes(uint8_t *x,long xlen); //gfshare_rand_func_t gfshare_fill_rand = _gfshare_fill_rand_using_random; -gfshare_rand_func_t gfshare_fill_rand = OS_randombytes; +//gfshare_rand_func_t gfshare_fill_rand = OS_randombytes; // ------------------------------------------------------[ Preparation ]---- -gfshare_ctx *_gfshare_ctx_init_core(unsigned char *sharenrs,uint32_t sharecount,unsigned char threshold,uint32_t size) +gfshare_ctx *_gfshare_ctx_init_core(uint8_t *sharenrs,uint32_t sharecount,uint8_t threshold,uint32_t size) { gfshare_ctx *ctx; ctx = XMALLOC(sizeof(struct _gfshare_ctx) + threshold * size); @@ -170,7 +170,7 @@ gfshare_ctx *_gfshare_ctx_init_core(unsigned char *sharenrs,uint32_t sharecount, } // Initialise a gfshare context for producing shares -gfshare_ctx *gfshare_ctx_init_enc(unsigned char *sharenrs,uint32_t sharecount,unsigned char threshold,uint32_t size) +gfshare_ctx *gfshare_ctx_init_enc(uint8_t *sharenrs,uint32_t sharecount,uint8_t threshold,uint32_t size) { uint32_t i; // can't have x[i] = 0 - that would just be a copy of the secret, in theory @@ -179,6 +179,7 @@ gfshare_ctx *gfshare_ctx_init_enc(unsigned char *sharenrs,uint32_t sharecount,un { if ( sharenrs[i] == 0 ) { + printf("null sharenrs error\n"); errno = EINVAL; return NULL; } @@ -187,7 +188,7 @@ gfshare_ctx *gfshare_ctx_init_enc(unsigned char *sharenrs,uint32_t sharecount,un } // Initialise a gfshare context for recombining shares -gfshare_ctx *gfshare_ctx_init_dec(unsigned char *sharenrs,uint32_t sharecount,uint32_t size) +gfshare_ctx *gfshare_ctx_init_dec(uint8_t *sharenrs,uint32_t sharecount,uint32_t size) { gfshare_ctx *ctx = _gfshare_ctx_init_core(sharenrs,sharecount,sharecount,size); if ( ctx != NULL ) @@ -199,26 +200,28 @@ gfshare_ctx *gfshare_ctx_init_dec(unsigned char *sharenrs,uint32_t sharecount,ui void gfshare_ctx_free(gfshare_ctx *ctx) { long len = sizeof(struct _gfshare_ctx) + ctx->buffersize; - gfshare_fill_rand((unsigned char*)ctx,len); + //gfshare_fill_rand((uint8_t*)ctx,len); + OS_randombytes((uint8_t *)ctx,len); XFREE(ctx); } // --------------------------------------------------------[ Splitting ]---- // Provide a secret to the encoder. (this re-scrambles the coefficients) -void gfshare_ctx_enc_setsecret(gfshare_ctx *ctx,unsigned char *secret) +void gfshare_ctx_enc_setsecret(gfshare_ctx *ctx,uint8_t *secret) { memcpy(ctx->buffer + ((ctx->threshold-1) * ctx->size),secret,ctx->size); - gfshare_fill_rand(ctx->buffer,(ctx->threshold-1) * ctx->size); + //gfshare_fill_rand(ctx->buffer,(ctx->threshold-1) * ctx->size); + OS_randombytes(ctx->buffer,(ctx->threshold-1) * ctx->size); } // Extract a share from the context. 'share' must be preallocated and at least 'size' bytes long. // 'sharenr' is the index into the 'sharenrs' array of the share you want. -void calc_share(unsigned char *buffer,int32_t size,int32_t M,uint32_t ilog,unsigned char *share) +void calc_share(uint8_t *buffer,int32_t size,int32_t M,uint32_t ilog,uint8_t *share) { uint32_t pos,coefficient;//,ilog = ctx_logs[ctx->sharenrs[sharenr]]; - //unsigned char *coefficient_ptr = buffer; - unsigned char *share_ptr,share_byte; + //uint8_t *coefficient_ptr = buffer; + uint8_t *share_ptr,share_byte; for (pos=0; posbuffer,ctx->size,ctx->threshold,ctx_logs[ctx->sharenrs[sharenr]],share); } -void calc_shares(unsigned char *shares,unsigned char *secret,int32_t size,int32_t width,int32_t M,int32_t N,unsigned char *sharenrs) +void calc_shares(uint8_t *shares,uint8_t *secret,int32_t size,int32_t width,int32_t M,int32_t N,uint8_t *sharenrs) { int32_t i; - unsigned char *buffer = calloc(M,width); + uint8_t *buffer = calloc(M,width); memset(shares,0,N*width); memcpy(buffer + ((M - 1) * size),secret,size); - gfshare_fill_rand(buffer,(M - 1) * size); + //gfshare_fill_rand(buffer,(M - 1) * size); + OS_randombytes(buffer,(M - 1) * size); for (i=0; i n || n >= 0xff ) // reserve 255 for illegal sharei + { + printf("illegal M.%d of N.%d\n",m,n); + return(-1); + } + randvals = calloc(1,65536); + OS_randombytes(randvals,65536); + memset(sharenrs,0,n); + if ( orig == 0 && n == m ) + { + for (i=0; i<255; i++) + valid[i] = (i + 1); + remains = orign = 255; + for (i=0; i> 8) % remains; + sharenrs[i] = valid[r]; + valid[r] = valid[--remains]; + } + /*while ( i < m ) + { + if ( j >= 65536 ) + { + gfshare_fill_rand(randvals,65536); + printf("refill j.%d\n",j); + j = 0; + } + r = (randvals[j++] % n); + if ( valid[r] != 0 ) + { + remains--; + i++; + sharenrs[r] = valid[r]; + //printf("%d ",sharenrs[i]); + valid[r] = 0; + } + }*/ + for (i=0; isharenrs,sharenrs,ctx->sharecount); } // Provide a share context with one of the shares. The 'sharenr' is the index into the 'sharenrs' array -void gfshare_ctx_dec_giveshare(gfshare_ctx *ctx,unsigned char sharenr,unsigned char *share) +void gfshare_ctx_dec_giveshare(gfshare_ctx *ctx,uint8_t sharenr,uint8_t *share) { memcpy(ctx->buffer + (sharenr * ctx->size),share,ctx->size); } // Extract the secret by interpolation of the shares. secretbuf must be allocated and at least 'size' bytes long -void gfshare_extract(unsigned char *secretbuf,uint8_t *sharenrs,int32_t N,uint8_t *buffer,int32_t size,int32_t width) +void gfshare_extract(uint8_t *secretbuf,uint8_t *sharenrs,int32_t N,uint8_t *buffer,int32_t size,int32_t width) { - uint32_t i,j,Li_top,Li_bottom; - unsigned char *secret_ptr,*share_ptr,sharei,sharej; + uint32_t i,j,Li_top,Li_bottom; uint8_t *secret_ptr,*share_ptr,sharei,sharej; memset(secretbuf,0,width); for (i=0; isharenrs,ctx->sharecount,ctx->buffer,ctx->size,ctx->size); } -int32_t init_sharenrs(unsigned char sharenrs[255],unsigned char *orig,int32_t m,int32_t n) +int32_t init_sharenrs(uint8_t sharenrs[255],uint8_t *orig,int32_t m,int32_t n) { - unsigned char *randvals,valid[255]; + uint8_t *randvals,valid[255]; int32_t i,j,r,remains,orign; if ( m > n || n >= 0xff ) // reserve 255 for illegal sharei { @@ -324,7 +415,7 @@ int32_t init_sharenrs(unsigned char sharenrs[255],unsigned char *orig,int32_t m, return(-1); } randvals = calloc(1,65536); - gfshare_fill_rand(randvals,65536); + OS_randombytes(randvals,65536); memset(sharenrs,0,n); if ( orig == 0 && n == m ) { @@ -335,10 +426,10 @@ int32_t init_sharenrs(unsigned char sharenrs[255],unsigned char *orig,int32_t m, { r = (randvals[i] % remains); sharenrs[i] = valid[r]; - //printf("%d ",sharenrs[i]); + printf("%d ",sharenrs[i]); valid[r] = valid[--remains]; } - //printf("FULL SET\n"); + printf("FULL SET\n"); } else { @@ -417,7 +508,7 @@ int test_m_of_n(int m,int n,int size,int maxiters) for (i=0; iorderid != orderid ) + { + printf("orderid mismatch %llu vs %llu\n",(long long)orderid,(long long)A->orderid); + return(clonestr("{\"error\":\"instantdex_BTCswap orderid mismatch\"}")); + } + if ( senderaddr == 0 || strcmp(A->A.base,base) != 0 || strcmp(A->A.rel,"BTC") != 0 ) + { + printf("senderaddr.%p base.(%s vs %s) rel.(%s vs %s)\n",senderaddr,A->A.base,base,A->A.rel,"BTC"); + return(clonestr("{\"error\":\"instantdex_BTCswap base or rel mismatch\"}")); + } + { + printf("satoshis mismatch %llu vs %llu\n",(long long)satoshis,(long long)instantdex_relsatoshis(A->A.price64,A->A.basevolume64)); + return(clonestr("{\"error\":\"instantdex_BTCswap satoshis mismatch\"}")); + } + if ( othersatoshis != A->A.basevolume64 ) + { + printf("othersatoshis mismatch %llu vs %llu\n",(long long)satoshis,(long long)A->A.basevolume64); + return(clonestr("{\"error\":\"instantdex_BTCswap satoshis mismatch\"}")); + } #endif diff --git a/iguana/SuperNET.h b/iguana/SuperNET.h index 9493cae20..34920028e 100644 --- a/iguana/SuperNET.h +++ b/iguana/SuperNET.h @@ -169,6 +169,9 @@ char *InstantDEX_hexmsg(struct supernet_info *myinfo,void *data,int32_t len,char bits256 bitcoin_pubkey33(uint8_t data[33],bits256 privkey); char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey,int32_t len); +uint8_t *cards777_recover(uint8_t *shares[],uint8_t *sharenrs,int32_t M,int32_t numcards,int32_t N); +int32_t cards777_calcmofn(uint8_t *allshares,uint8_t *myshares[],uint8_t *sharenrs,int32_t M,bits256 *xoverz,int32_t numcards,int32_t N); +int32_t init_sharenrs(unsigned char sharenrs[255],unsigned char *orig,int32_t m,int32_t n); #endif diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index 4bbba662c..f9d03d329 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -1099,11 +1099,11 @@ int32_t bitcoin_scriptget(struct iguana_info *coin,int32_t *hashtypep,struct vin return(vp->spendlen); } -int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,int32_t *scriptlens,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V) +int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,int32_t *scriptlens,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighashsingle) { bits256 txid,sigtxid,revsigtxid; char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; uint8_t *sig,*pubkey,*saveinput; struct vin_info *vp; - int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype; + int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts = msgtx->tx_out; vpnstr[0] = 0; *signedtx = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); @@ -1116,7 +1116,7 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** for (i=0; ivins[i].scriptlen = 0; sig = &msgtx->vins[vini].script[1]; - siglen = msgtx->vins[vini].script[0] - 1; + siglen = msgtx->vins[vini].script[0]; vp->vin = msgtx->vins[vini]; flag = 0; for (k=0; k<2; k++) @@ -1127,6 +1127,11 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** printf("cant get script for (%s).v%d\n",bits256_str(str,vp->vin.prev_hash),vp->vin.prev_vout); continue; } + if ( sighashsingle != 0 && vini == 0 ) + { + msgtx->tx_out = 1; + hashtype = SIGHASH_SINGLE; + } else msgtx->tx_out = numvouts; msgtx->vins[vini].script = vp->spendscript; msgtx->vins[vini].scriptlen = vp->spendlen; for (j=0; jN; j++) @@ -1143,6 +1148,7 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** if ( n2 > 0 ) { n2 += iguana_rwnum(1,&serialized[n2],sizeof(hashtype),&hashtype); + printf("hashtype.%d [%02x]\n",hashtype,sig[siglen-1]); revsigtxid = bits256_doublesha256(txidstr,serialized,n2); for (i=0; isigners[j].siglen = bitcoin_sign(vp->signers[j].sig,sizeof(vp->signers[j].sig),sigtxid.bytes,sizeof(sigtxid),vp->signers[j].privkey); sig = vp->signers[j].sig; + sig[vp->signers[j].siglen++] = hashtype; siglen = vp->signers[j].siglen; msgtx->vins[vini].scriptlen = bitcoin_scriptsig(msgtx->vins[vini].script,0,(const struct vin_info *)vp); - printf("SIGNEDTX plen.%d siglen.%d\n",plen,siglen); + for (i=0; isigners[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) { @@ -1161,9 +1170,9 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** } else { - printf("SIG.%d VERIFIED\n",vini); *signedtx = iguana_rawtxbytes(coin,0,msgtx); *signedtxidp = msgtx->txid; + printf("SIG.%d VERIFIED %s\n",vini,*signedtx); flag = 1; break; } @@ -1214,7 +1223,7 @@ int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **si scriptlens = calloc(numvins,sizeof(*scriptlens)); for (i=0; ihasheaders = hasheaders; - if ( strcmp(chain->symbol,"bitcoin") == 0 ) + chain->minoutput = 10000; + if ( strcmp(chain->symbol,"BTC") == 0 ) { chain->unitval = 0x1d; + chain->txfee = 10000; } else { + if ( strcmp(chain->symbol,"LTC") == 0 ) + chain->txfee = 100000; + else chain->txfee = 1000000; if ( chain->unitval == 0 ) chain->unitval = 0x1e; } diff --git a/iguana/iguana_instantdex.c b/iguana/iguana_instantdex.c index 0c1932799..f8f1cb8b9 100755 --- a/iguana/iguana_instantdex.c +++ b/iguana/iguana_instantdex.c @@ -380,8 +380,8 @@ cJSON *instantdex_acceptsendjson(struct instantdex_accept *ap) char *instantdex_parse(struct supernet_info *myinfo,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,uint8_t *data,int32_t datalen) { - char cmdstr[16],*traderip,*orderidstr; struct exchange_info *exchange; uint64_t orderid; - struct instantdex_accept A,*ap; + char cmdstr[16],*traderip,*orderidstr,*retstr; struct exchange_info *exchange; uint64_t orderid; + struct instantdex_accept A,*ap = 0; exchange = exchanges777_find("bitcoin"); memset(cmdstr,0,sizeof(cmdstr)), memcpy(cmdstr,msg->cmd,sizeof(msg->cmd)); if ( argjson != 0 ) @@ -397,15 +397,21 @@ char *instantdex_parse(struct supernet_info *myinfo,struct instantdex_msghdr *ms orderid = calc_nxt64bits(orderidstr); if ( (ap= instantdex_acceptablefind(exchange,0,0,orderid,"*","*")) != 0 ) A = *ap; - } else instantdex_acceptextract(&A,argjson); + } else if ( instantdex_acceptextract(&A,argjson) < 0 ) + return(clonestr("{\"error\":\"hash txid mismatches orderid\"}")); if ( strncmp(cmdstr,"BTC",3) == 0 ) - return(instantdex_BTCswap(myinfo,exchange,&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen)); + retstr = instantdex_BTCswap(myinfo,exchange,&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen); else if ( strncmp(cmdstr,"NXT",3) == 0 ) - return(instantdex_NXTswap(myinfo,exchange,&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen)); + retstr = instantdex_NXTswap(myinfo,exchange,&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen); else if ( strncmp(cmdstr,"ALT",3) == 0 ) - return(instantdex_ALTswap(myinfo,exchange,&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen)); + retstr = instantdex_ALTswap(myinfo,exchange,&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen); else if ( strncmp(cmdstr,"PAX",3) == 0 ) - return(instantdex_PAXswap(myinfo,exchanges777_find("PAX"),&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen)); + retstr = instantdex_PAXswap(myinfo,exchanges777_find("PAX"),&A,cmdstr+3,msg,argjson,remoteaddr,signerbits,data,datalen); + if ( ap != 0 ) + { + ap->statusjson = A.statusjson; + ap->pendingvolume64 = A.pendingvolume64; + } else return(clonestr("{\"error\":\"unrecognized atomic swap family\"}")); } return(clonestr("{\"error\":\"request needs argjson\"}")); diff --git a/iguana/iguana_peers.c b/iguana/iguana_peers.c index 319855260..89ebd5f2d 100755 --- a/iguana/iguana_peers.c +++ b/iguana/iguana_peers.c @@ -762,7 +762,7 @@ uint32_t iguana_possible_peer(struct iguana_info *coin,char *ipaddr) printf("error updating status for (%s) ind.%d\n",ipaddr,iA->hh.itemind); iguana_iAddriterator(coin,iA); } else printf("ignore.(%s) lastconnect.%u lastkilled.%u numconnects.%d\n",ipaddr,iA->lastconnect,iA->lastkilled,iA->numconnects); - } else printf("skip.(%s) ind.%d status.%d\n",ipaddr,iA->hh.itemind,iA->status); + } //else printf("skip.(%s) ind.%d status.%d\n",ipaddr,iA->hh.itemind,iA->status); } else printf("cant find (%s) which should have been created\n",ipaddr); } else printf("reject ipaddr.(%s)\n",ipaddr); } diff --git a/iguana/iguana_pubkeys.c b/iguana/iguana_pubkeys.c index 50fe6547a..a5298137d 100755 --- a/iguana/iguana_pubkeys.c +++ b/iguana/iguana_pubkeys.c @@ -668,7 +668,7 @@ int32_t btc_wif2priv(uint8_t *addrtypep,uint8_t privkey[32],char *wifstr) len = (int32_t)cstr->len; char tmp[138]; btc_priv2wif(tmp,privkey,*addrtypep); - printf("addrtype.%02x wifstr.(%llx) len.%d\n",*addrtypep,*(long long *)privkey,len); + printf("addrtype.%02x wifstr.(%llx) privlen.%d\n",*addrtypep,*(long long *)privkey,len); cstr_free(cstr,true); } return(len); diff --git a/iguana/main.c b/iguana/main.c index 02d1400f3..78bffcf62 100644 --- a/iguana/main.c +++ b/iguana/main.c @@ -298,11 +298,760 @@ void mainloop(struct supernet_info *myinfo) } } +int32_t calcmofn(uint8_t *allshares,uint8_t *myshares[],uint8_t *sharenrs,int32_t M,uint8_t *data,int32_t datasize,int32_t N) +{ + int32_t j; + calc_shares(allshares,(void *)data,datasize,datasize,M,N,sharenrs); + for (j=0; j 2006,2015 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +//#include "config.h" +//#include "libgfshare.h" +//#include "libgfshare_tables.h" + +#ifndef LIBGFSHARE_H +#define LIBGFSHARE_H + + +typedef struct _gfshare_ctx gfshare_ctx; + +typedef void (*gfshare_rand_func_t)(uint8_t*, unsigned int); + +/* This will, use random(). It's not very good so you should not use it unless + * you must. If you can't be bothered to write your own, be sure to srandom() + * before you use any of the gfshare_ctx_enc_* functions + */ +extern const gfshare_rand_func_t gfshare_bad_idea_but_fill_rand_using_random; +/* This must be filled out before running any of the gfshare_ctx_enc_* calls + * or bad things will happen since it is initialised to NULL be default. + * You should fill this with a routine which uses urandom or similar ideally. + * If you cannot do that on your platform, you can use the function provided + * which does random() calls, but I recommend against it unless you must. + */ +extern gfshare_rand_func_t gfshare_fill_rand; + +/* ------------------------------------------------------[ Preparation ]---- */ + +/* Initialise a gfshare context for producing shares */ +gfshare_ctx* gfshare_ctx_init_enc(uint8_t* /* sharenrs */, + unsigned int /* sharecount */, + uint8_t /* threshold */, + unsigned int /* size */); + +/* Initialise a gfshare context for recombining shares */ +gfshare_ctx* gfshare_ctx_init_dec(uint8_t* /* sharenrs */, + unsigned int /* sharecount */, + unsigned int /* size */); + +/* Free a share context's memory. */ +void gfshare_ctx_free(gfshare_ctx* /* ctx */); + +/* --------------------------------------------------------[ Splitting ]---- */ + +/* Provide a secret to the encoder. (this re-scrambles the coefficients) */ +void gfshare_ctx_enc_setsecret(gfshare_ctx* /* ctx */, + uint8_t* /* secret */); + +/* Extract a share from the context. + * 'share' must be preallocated and at least 'size' bytes long. + * 'sharenr' is the index into the 'sharenrs' array of the share you want. + */ +void gfshare_ctx_enc_getshare(gfshare_ctx* /* ctx */, + uint8_t /* sharenr */, + uint8_t* /* share */); + +/* ----------------------------------------------------[ Recombination ]---- */ + +/* Inform a recombination context of a change in share indexes */ +void gfshare_ctx_dec_newshares(gfshare_ctx* /* ctx */, + uint8_t* /* sharenrs */); + +/* Provide a share context with one of the shares. + * The 'sharenr' is the index into the 'sharenrs' array + */ +void gfshare_ctx_dec_giveshare(gfshare_ctx* /* ctx */, + uint8_t /* sharenr */, + uint8_t* /* share */); + +/* Extract the secret by interpolation of the shares. + * secretbuf must be allocated and at least 'size' bytes long + */ +void gfshare_ctx_dec_extract(gfshare_ctx* /* ctx */, + uint8_t* /* secretbuf */); + +#endif /* LIBGFSHARE_H */ + + +#include +#include +#include + +#define XMALLOC malloc +#define XFREE free + +struct _gfshare_ctx { + unsigned int sharecount; + unsigned int threshold; + unsigned int size; + uint8_t* sharenrs; + uint8_t* buffer; + unsigned int buffersize; +}; + +static void +_gfshare_fill_rand_using_random( uint8_t* buffer, + unsigned int count ) +{ + unsigned int i; + for( i = 0; i < count; ++i ) + buffer[i] = (random() & 0xff00) >> 8; /* apparently the bottom 8 aren't + * very random but the middles ones + * are + */ +} +const gfshare_rand_func_t gfshare_bad_idea_but_fill_rand_using_random = +_gfshare_fill_rand_using_random; +gfshare_rand_func_t gfshare_fill_rand = NULL; + +/* ------------------------------------------------------[ Preparation ]---- */ + +static gfshare_ctx * +_gfshare_ctx_init_core( uint8_t *sharenrs, + unsigned int sharecount, + uint8_t threshold, + unsigned int size ) +{ + gfshare_ctx *ctx; + + ctx = XMALLOC( sizeof(struct _gfshare_ctx) ); + if( ctx == NULL ) + return NULL; /* errno should still be set from XMALLOC() */ + + ctx->sharecount = sharecount; + ctx->threshold = threshold; + ctx->size = size; + ctx->sharenrs = XMALLOC( sharecount ); + + if( ctx->sharenrs == NULL ) { + int saved_errno = errno; + XFREE( ctx ); + errno = saved_errno; + return NULL; + } + + memcpy( ctx->sharenrs, sharenrs, sharecount ); + ctx->buffersize = threshold * size; + ctx->buffer = XMALLOC( ctx->buffersize ); + + if( ctx->buffer == NULL ) { + int saved_errno = errno; + XFREE( ctx->sharenrs ); + XFREE( ctx ); + errno = saved_errno; + return NULL; + } + + return ctx; +} + +/* Initialise a gfshare context for producing shares */ +gfshare_ctx * +gfshare_ctx_init_enc( uint8_t* sharenrs, + unsigned int sharecount, + uint8_t threshold, + unsigned int size ) +{ + unsigned int i; + + for (i = 0; i < sharecount; i++) { + if (sharenrs[i] == 0) { + /* can't have x[i] = 0 - that would just be a copy of the secret, in + * theory (in fact, due to the way we use exp/log for multiplication and + * treat log(0) as 0, it ends up as a copy of x[i] = 1) */ + errno = EINVAL; + return NULL; + } + } + + return _gfshare_ctx_init_core( sharenrs, sharecount, threshold, size ); +} + +/* Initialise a gfshare context for recombining shares */ +gfshare_ctx* +gfshare_ctx_init_dec( uint8_t* sharenrs, + unsigned int sharecount, + unsigned int size ) +{ + gfshare_ctx *ctx = _gfshare_ctx_init_core( sharenrs, sharecount, sharecount, size ); + + if( ctx != NULL ) + ctx->threshold = 0; + + return ctx; +} + +/* Free a share context's memory. */ +void +gfshare_ctx_free( gfshare_ctx* ctx ) +{ + gfshare_fill_rand( ctx->buffer, ctx->buffersize ); + gfshare_fill_rand( ctx->sharenrs, ctx->sharecount ); + XFREE( ctx->sharenrs ); + XFREE( ctx->buffer ); + gfshare_fill_rand( (uint8_t*)ctx, sizeof(struct _gfshare_ctx) ); + XFREE( ctx ); +} + +/* --------------------------------------------------------[ Splitting ]---- */ + +/* Provide a secret to the encoder. (this re-scrambles the coefficients) */ +void +gfshare_ctx_enc_setsecret( gfshare_ctx* ctx, + uint8_t* secret) +{ + memcpy( ctx->buffer + ((ctx->threshold-1) * ctx->size), + secret, + ctx->size ); + gfshare_fill_rand( ctx->buffer, (ctx->threshold-1) * ctx->size ); +} + +/* Extract a share from the context. + * 'share' must be preallocated and at least 'size' bytes long. + * 'sharenr' is the index into the 'sharenrs' array of the share you want. + */ +void +gfshare_ctx_enc_getshare( gfshare_ctx* ctx, + uint8_t sharenr, + uint8_t* share) +{ + unsigned int pos, coefficient; + unsigned int ilog = logs[ctx->sharenrs[sharenr]]; + uint8_t *coefficient_ptr = ctx->buffer; + uint8_t *share_ptr; + for( pos = 0; pos < ctx->size; ++pos ) + share[pos] = *(coefficient_ptr++); + for( coefficient = 1; coefficient < ctx->threshold; ++coefficient ) { + share_ptr = share; + for( pos = 0; pos < ctx->size; ++pos ) { + uint8_t share_byte = *share_ptr; + if( share_byte ) + share_byte = exps[ilog + logs[share_byte]]; + *share_ptr++ = share_byte ^ *coefficient_ptr++; + } + } +} + +/* ----------------------------------------------------[ Recombination ]---- */ + +/* Inform a recombination context of a change in share indexes */ +void +gfshare_ctx_dec_newshares( gfshare_ctx* ctx, + uint8_t* sharenrs) +{ + memcpy( ctx->sharenrs, sharenrs, ctx->sharecount ); +} + +/* Provide a share context with one of the shares. + * The 'sharenr' is the index into the 'sharenrs' array + */ +void +gfshare_ctx_dec_giveshare( gfshare_ctx* ctx, + uint8_t sharenr, + uint8_t* share ) +{ + memcpy( ctx->buffer + (sharenr * ctx->size), share, ctx->size ); +} + +/* Extract the secret by interpolation of the shares. + * secretbuf must be allocated and at least 'size' bytes long + */ +void +gfshare_ctx_dec_extract( gfshare_ctx* ctx, + uint8_t* secretbuf ) +{ + unsigned int i, j; + uint8_t *secret_ptr, *share_ptr, sharei,sharej; + + for( i = 0; i < ctx->size; ++i ) + secretbuf[i] = 0; + + for( i = 0; i < ctx->sharecount; ++i ) + { + // Compute L(i) as per Lagrange Interpolation + unsigned Li_top = 0, Li_bottom = 0; + if ( (sharei= ctx->sharenrs[i]) != 0 ) + { + for ( j = 0; j < ctx->sharecount; ++j ) + { + if ( i != j && sharei != (sharej= ctx->sharenrs[j]) ) + { + if ( sharej == 0 ) + continue; // skip empty share */ + Li_top += logs[sharej]; + if ( Li_top >= 0xff ) + Li_top -= 0xff; + Li_bottom += logs[sharei ^ sharej]; + if ( Li_bottom >= 0xff ) + Li_bottom -= 0xff; + } + } + if ( Li_bottom > Li_top ) + Li_top += 0xff; + Li_top -= Li_bottom; // Li_top is now log(L(i)) + secret_ptr = secretbuf, share_ptr = ctx->buffer + (ctx->size * i); + for (j=0; jsize; j++) + { + if ( *share_ptr != 0 ) + *secret_ptr ^= exps[Li_top + logs[*share_ptr]]; + share_ptr++, secret_ptr++; + } + } + } +} +void calc_share(uint8_t *buffer,int32_t size,int32_t M,uint32_t ilog,uint8_t *share) +{ + uint32_t pos,coefficient;//,ilog = ctx_logs[ctx->sharenrs[sharenr]]; + //uint8_t *coefficient_ptr = buffer; + uint8_t *share_ptr,share_byte; + for (pos=0; pos + +int32_t test(int32_t M,int32_t N,int32_t datasize) +{ + int ok = 1, i; + uint8_t * secret = malloc(datasize); + uint8_t *shares[255]; + uint8_t *recomb = malloc(datasize); + uint8_t sharenrs[255],newsharenrs[255];// = (uint8_t *)strdup("0124z89abehtr"); + gfshare_ctx *G; + gfshare_fill_rand = gfshare_bad_idea_but_fill_rand_using_random; + for (i=0; i> 8; + /* Stage 2, split it N ways with a threshold of M */ + G = gfshare_ctx_init_enc( sharenrs, N, M, datasize ); + gfshare_ctx_enc_setsecret( G, secret ); + for (i=0; i n || n >= 0xff ) // reserve 255 for illegal sharei + { + printf("illegal M.%d of N.%d\n",m,n); + return(-1); + } + randvals = calloc(1,65536); + OS_randombytes(randvals,65536); + if ( orig == 0 && n == m ) + { + memset(sharenrs,0,n); + for (i=0; i<255; i++) + valid[i] = (i + 1); + remains = orign = 255; + for (i=0; iNXTAPIURL,"http://127.0.0.1:"); @@ -351,14 +1100,18 @@ void iguana_main(void *arg) #ifdef __APPLE__ sleep(1); char *str; - strcpy(MYINFO.rpcsymbol,"BTCD"); + strcpy(MYINFO.rpcsymbol,"BTC"); iguana_launchcoin(MYINFO.rpcsymbol,cJSON_Parse("{}")); - if ( 0 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"wallet\":\"password\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":128,\"maxpeers\":3,\"newcoin\":\"BTCD\",\"active\":0}"),0)) != 0 ) + if ( 0 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"wallet\":\"password\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":128,\"maxpeers\":3,\"newcoin\":\"BTC\",\"active\":0}"),0)) != 0 ) { printf("got.(%s)\n",str); free(str); } + sleep(1); + static bits256 txid; + bitcoin_txtest(iguana_coinfind(MYINFO.rpcsymbol),"000",txid); + getchar(); #endif } if ( arg != 0 ) diff --git a/iguana/swaps/iguana_BTCswap.c b/iguana/swaps/iguana_BTCswap.c index e03235561..311b39ca0 100755 --- a/iguana/swaps/iguana_BTCswap.c +++ b/iguana/swaps/iguana_BTCswap.c @@ -14,6 +14,21 @@ ******************************************************************************/ #include "../exchanges/bitcoin.h" +/* +bitcoin_pubkey33(pubkey,myinfo->persistent_priv); +bitcoin_address(coinaddr,other->chain->pubtype,pubkey,sizeof(pubkey)); +bitcoin_addr2rmd160(&addrtype,secret160,coinaddr); +scriptlen = bitcoin_cltvscript(coinbtc->chain->p2shtype,p2sh_coinaddr,p2sh_rmd160,script,0,senderaddr,otheraddr,secret160,locktime); +if ( jobj(argjson,"p2sh") != 0 ) +{ + if ( strcmp(jstr(argjson,"p2sh"),p2sh_coinaddr) != 0 ) + { + printf("mismatched p2sh.(%s) vs (%s)\n",jstr(argjson,"p2sh"),p2sh_coinaddr); + return(clonestr("{\"error\":\"instantdex_BTCswap base or rel mismatch\"}")); + } +} +*/ +#define INSTANTDEX_DONATION 2000 // https://github.com/TierNolan/bips/blob/bip4x/bip-atom.mediawiki @@ -24,23 +39,23 @@ uint64_t instantdex_relsatoshis(uint64_t price,uint64_t volume) else return(dstr(price) * volume); } -bits256 instantdex_sharedpub256(uint8_t pubkey[33],bits256 privkey,bits256 hash,int32_t n) +bits256 instantdex_sharedpub256(bits256 *sharedprivp,uint8_t pubkey[33],bits256 privkey,bits256 hash,int32_t n) { - bits256 tmppriv,shared,iters; int32_t i; + bits256 shared,iters; int32_t i; iters = shared = curve25519_shared(privkey,hash); for (i=0; ibytes,shared.bytes,sizeof(shared),iters.bytes,sizeof(iters)); + return(bitcoin_pubkey33(pubkey,*sharedprivp)); } -int32_t instantdex_pubkeyargs(cJSON *argjson,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) +int32_t instantdex_pubkeyargs(bits256 *sharedprivs,cJSON *argjson,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) { char buf[3]; int32_t i,n; bits256 tmp; uint8_t pubkey[33]; sprintf(buf,"%c0",'A' - 0x02 + firstbyte); for (i=n=0; ivalue; + //printf("(%.8f vs %.8f)\n",dstr(atx_value),dstr(value)); + if ( atx_value == value ) + return(vin); + else if ( atx_value > value ) + { + gap = (atx_value - value); + if ( above == 0 || gap < above ) + { + above = gap; + abovevin = vin; + } + } + else if ( mode == 0 ) + { + gap = (value - atx_value); + if ( below == 0 || gap < below ) + { + below = gap; + belowvin = vin; + } + } + } + if ( (vin= (abovevin != 0) ? abovevin : belowvin) == 0 && mode == 1 ) + vin = unspents; + return(vin); +} + +struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *numunspentsp) { - char changeaddr[64]; - int32_t numinputs; - uint64_t txfee,input_satoshis,satoshis; - struct bitcoin_unspent inputs[]; -};*/ + struct bitcoin_unspent *ups = calloc(1,sizeof(*ups)); + // struct bitcoin_unspent { bits256 txid,privkey; uint64_t value; int32_t vout; }; + *numunspentsp = 0; + return(ups); +} -char *instantdex_bailintx(struct iguana_info *coin,bits256 *txidp,struct bitcoin_spend *spend,bits256 A0,bits256 B0,uint8_t x[20],int32_t isbob) +struct bitcoin_spend *instantdex_spendset(struct supernet_info *myinfo,struct iguana_info *coin,uint64_t satoshis,uint64_t donation) { -/*Input value: B + 2*fb + change -Input source: (From Bob's coins, multiple inputs are allowed) - Output 0 value: B - ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL - Output 1 value: fb - ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUALVERIFY pub-A1 OP_CHECKSIG - Output 2 value: change - ScriptPubKey 2: <= 100 bytes - P2SH Redeem: OP_2 pub-A1 pub-B1 OP_2 OP_CHECKMULTISIG + int32_t i,mode,numunspents,maxinputs = 1024; int64_t remains; struct bitcoin_unspent *ptr,*up; + struct bitcoin_unspent *ups; struct bitcoin_spend *spend; + if ( (ups= iguana_unspentsget(myinfo,coin,&numunspents)) == 0 ) + return(0); + spend = calloc(1,sizeof(*spend) + sizeof(*spend->inputs) * maxinputs); + spend->satoshis = satoshis; + spend->txfee = coin->chain->txfee; + if ( strcmp(coin->symbol,"BTC") == 0 ) + remains = spend->txfee + spend->satoshis + donation; + ptr = spend->inputs; + for (i=0; i=0; mode--) + if ( (up= instantdex_bestfit(coin,ups,numunspents,remains,mode)) != 0 ) + break; + if ( up != 0 ) + { + spend->input_satoshis += up->value; + spend->inputs[spend->numinputs++] = *up; + if ( spend->input_satoshis >= satoshis ) + { + spend->netamount = (spend->input_satoshis - spend->txfee - donation); + spend->change = (spend->input_satoshis - spend->netamount); + printf("numinputs %d sum %.8f vs satoshis %.8f change %.8f -> txfee %.8f\n",spend->numinputs,dstr(spend->input_satoshis),dstr(satoshis),dstr(spend->change),dstr(spend->input_satoshis - spend->change - spend->netamount)); + break; + } + remains -= up->value; + } else break; + } + if ( spend->input_satoshis >= (satoshis + spend->txfee) ) + { + realloc(spend,sizeof(*spend) + sizeof(*spend->inputs) * spend->numinputs); + return(spend); + } + else + { + free(spend); + return(0); + } +} + +/* +Name: Bob.Bail.In + Input value: B + 2*fb + change + Input source: (From Bob's coins, multiple inputs are allowed) + vout0 value: B, ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL + vout1 value: fb, ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUALVERIFY pub-A1 OP_CHECKSIG + vout2 value: change, ScriptPubKey 2: <= 100 bytes + P2SH Redeem: OP_2 pub-A1 pub-B1 OP_2 OP_CHECKMULTISIG Name: Alice.Bail.In - Input value: A + 2*fa + change - Input source: (From Alice's altcoins, multiple inputs are allowed) - Output 0 value: A - ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL - Output 1 value: fa - ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUAL - Output 2 value: change - ScriptPubKey 2: <= 100 bytes*/ + vins: A + 2*fa + change, Input source: (From Alice's altcoins, multiple inputs are allowed) + vout0 value: A, ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL + vout1 value: fa, ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUAL + vout2 value: change, ScriptPubKey 2: <= 100 bytes +*/ +char *instantdex_bailintx(struct iguana_info *coin,bits256 *txidp,struct bitcoin_spend *spend,bits256 A0,bits256 B0,uint8_t x[20],int32_t isbob) +{ uint64_t change; char *rawtxstr,*signedtx; struct vin_info *V; bits256 txid,signedtxid; int32_t p2shlen,i; cJSON *txobj; int32_t scriptv0len,scriptv1len,scriptv2len; uint8_t p2shscript[256],scriptv0[128],scriptv1[128],changescript[128],pubkey[35]; @@ -114,19 +202,98 @@ Name: Alice.Bail.In bitcoin_verifytx(coin,&signedtxid,&signedtx,rawtxstr,V); free(rawtxstr), free(V); if ( signedtx != 0 ) - printf("signed bob_bailin.%s (%s)\n",bits256_str(str,signedtxid),signedtx); + printf("signed %s_bailin.%s (%s)\n",isbob!=0?"bob":"alice",bits256_str(str,signedtxid),signedtx); else printf("error generating signedtx\n"); free_json(txobj); *txidp = txid; return(signedtx); } -int32_t instantdex_calcx20(char hexstr[41],uint8_t *p2shscript,uint8_t firstbyte,bits256 pub3) +cJSON *instantdex_bailinspend(struct iguana_info *coin,bits256 privkey,uint64_t amount) +{ + bits256 hash; int32_t n; cJSON *txobj; + int32_t scriptv0len; uint8_t p2shscript[256],rmd160[20],scriptv0[128],pubkey[35]; + bitcoin_pubkey33(pubkey,privkey); + n = bitcoin_pubkeyspend(p2shscript,0,pubkey); + vcalc_sha256(0,hash.bytes,p2shscript,n); + calc_rmd160(0,rmd160,hash.bytes,sizeof(hash.bytes)); + scriptv0len = bitcoin_p2shspend(scriptv0,0,rmd160); + txobj = bitcoin_createtx(coin,0); + bitcoin_addoutput(coin,txobj,scriptv0,scriptv0len,amount); + return(txobj); +} + +/* +Name: Bob.Payout +vin0: A, Input source: Alice.Bail.In:0 +vin1: fa, Input source: Alice.Bail.In:1 +vout0: A, ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL; P2SH Redeem: pub-B2 OP_CHECKSIG + + Name: Alice.Payout +vin0: B, Input source: Bob.Bail.In:0 +vin1: fb, Input source: Bob.Bail.In:1 +vout0: B, ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL; P2SH Redeem: pub-A2 OP_CHECKSIG +*/ + +char *instantdex_bailinsign(struct iguana_info *coin,bits256 bailinpriv,char *sigstr,int32_t *siglenp,bits256 *txidp,struct vin_info *V,cJSON *txobj,int32_t isbob) +{ + char *rawtxstr,*signedtx; + rawtxstr = bitcoin_json2hex(coin,txidp,txobj); + char str[65]; printf("%s_payout.%s (%s)\n",isbob!=0?"bob":"alice",bits256_str(str,*txidp),rawtxstr); + V->signers[isbob].privkey = bailinpriv; + bitcoin_verifytx(coin,txidp,&signedtx,rawtxstr,V); + *siglenp = V->signers[isbob].siglen; + init_hexbytes_noT(sigstr,V->signers[isbob].sig,*siglenp); + free(rawtxstr); + if ( signedtx != 0 ) + printf("signed %s_payout.%s (%s) sig.%s\n",isbob!=0?"bob":"alice",bits256_str(str,*txidp),signedtx,sigstr); + else printf("error generating signedtx\n"); + free_json(txobj); + return(signedtx); +} + + +char *instantdex_payouttx(struct iguana_info *coin,char *sigstr,int32_t *siglenp,bits256 *txidp,bits256 *sharedprivs,bits256 bailintxid,int64_t amount,int64_t txfee,int32_t isbob,char *othersigstr) +{ + struct vin_info V; cJSON *txobj; + txobj = instantdex_bailinspend(coin,sharedprivs[1],amount); + bitcoin_addinput(coin,txobj,bailintxid,0,0xffffffff); + bitcoin_addinput(coin,txobj,bailintxid,1,0xffffffff); + memset(&V,0,sizeof(V)); + if ( othersigstr != 0 ) + { + printf("OTHERSIG.(%s)\n",othersigstr); + V.signers[isbob ^ 1].siglen = (int32_t)strlen(othersigstr) >> 1; + decode_hex(V.signers[isbob ^ 1].sig,V.signers[isbob ^ 1].siglen,othersigstr); + } + return(instantdex_bailinsign(coin,sharedprivs[0],sigstr,siglenp,txidp,&V,txobj,isbob)); +} + +/* +Name: Alice.Refund +vin0: A, Input source: Alice.Bail.In:0 +vout0: A - fa, ScriptPubKey: OP_HASH160 Hash160(P2SH) OP_EQUAL; P2SH Redeem: pub-A3 OP_CHECKSIG +Locktime: current block height + ((T/2)/(altcoin block rate)) + +Name: Bob.Refund +vin0: B, Input source: Bob.Bail.In:0 +vout0: B - fb, ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL; P2SH Redeem: pub-B3 OP_CHECKSIG +Locktime: (current block height) + (T / 10 minutes) +*/ +char *instantdex_refundtx(struct iguana_info *coin,bits256 *txidp,bits256 bailinpriv,bits256 priv2,bits256 bailintxid,int64_t amount,int64_t txfee,int32_t isbob) +{ + char sigstr[256]; int32_t siglen; struct vin_info V; cJSON *txobj; + txobj = instantdex_bailinspend(coin,priv2,amount - txfee); + bitcoin_addinput(coin,txobj,bailintxid,0,0xffffffff); + return(instantdex_bailinsign(coin,bailinpriv,sigstr,&siglen,txidp,&V,txobj,isbob)); +} + +int32_t instantdex_calcx20(char hexstr[41],uint8_t *p2shscript,uint8_t firstbyte,bits256 pub) { - uint8_t pubkey[33],script[64],rmd160[20]; int32_t n; bits256 hash; - memcpy(pubkey+1,pub3.bytes,sizeof(pub3)), pubkey[0] = firstbyte; + uint8_t pubkey[33],rmd160[20]; int32_t n; bits256 hash; + memcpy(pubkey+1,pub.bytes,sizeof(pub)), pubkey[0] = firstbyte; n = bitcoin_pubkeyspend(p2shscript,0,pubkey); - vcalc_sha256(0,hash.bytes,script,n); + vcalc_sha256(0,hash.bytes,p2shscript,n); calc_rmd160(0,rmd160,hash.bytes,sizeof(hash.bytes)); init_hexbytes_noT(hexstr,rmd160,sizeof(rmd160)); return(n); @@ -134,17 +301,17 @@ int32_t instantdex_calcx20(char hexstr[41],uint8_t *p2shscript,uint8_t firstbyte char *instantdex_btcoffer(struct supernet_info *myinfo,struct exchange_info *exchange,char *othercoin,double othervolume,double maxprice) // Bob sending to network (Alice) { - char *str,coinaddr[64],xstr[41]; uint8_t xscript[64]; struct iguana_info *other; - struct instantdex_accept A; cJSON *newjson; bits256 hash,pub3; + char *str,coinaddr[64],xstr[41]; uint8_t xscript[64]; struct iguana_info *other; int32_t isbob = 1; + struct instantdex_accept A; cJSON *newjson; bits256 hash,pub3,sharedprivs[4]; if ( othercoin == 0 || (other= iguana_coinfind(othercoin)) == 0 ) return(clonestr("{\"error\":\"invalid othercoin\"}")); hash = instantdex_acceptset(&A,othercoin,"BTC",INSTANTDEX_OFFERDURATION,1,-1,maxprice,othervolume,myinfo->myaddr.nxt64bits); newjson = instantdex_acceptsendjson(&A); - if ( instantdex_pubkeyargs(newjson,4,myinfo->persistent_priv,hash,0x03) != 4 ) + if ( instantdex_pubkeyargs(sharedprivs,newjson,4,myinfo->persistent_priv,hash,0x02+isbob) != 4 ) return(clonestr("{\"error\":\"highly unlikely run of 02 pubkeys\"}")); pub3 = jbits256(newjson,"B3"); jdelete(newjson,"B3"); - instantdex_calcx20(xstr,xscript,0x03,pub3); + instantdex_calcx20(xstr,xscript,0x02+isbob,pub3); jaddstr(newjson,"x",xstr); if ( coinaddr[0] != 0 ) jaddstr(newjson,othercoin,coinaddr); @@ -156,15 +323,87 @@ char *instantdex_btcoffer(struct supernet_info *myinfo,struct exchange_info *exc return(instantdex_sendcmd(myinfo,newjson,"BTCoffer",myinfo->ipaddr,INSTANTDEX_HOPS)); } +void instantdex_pendingnotice(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap,struct instantdex_accept *A) +{ + printf("need to start monitoring thread\n"); + ap->pendingvolume64 -= A->A.basevolume64; +} + +cJSON *instantdex_newjson(struct supernet_info *myinfo,bits256 *A0p,bits256 *B0p,bits256 *sharedprivs,uint8_t secret160[20],int32_t isbob,cJSON *argjson,bits256 hash) +{ + cJSON *newjson = cJSON_CreateObject(); char *xstr; + if ( instantdex_pubkeyargs(sharedprivs,newjson,3+isbob,myinfo->persistent_priv,hash,0x02+isbob) != 3 ) + return(0); + if ( isbob == 0 ) + *A0p = jbits256(newjson,"A0"); + else *A0p = jbits256(argjson,"A0"); + *B0p = jbits256(argjson,"B0"); + if ( (xstr= jstr(argjson,"x")) != 0 ) + { + decode_hex(secret160,20,xstr); + jaddstr(newjson,"x",xstr); + } + return(newjson); +} + +char *instantdex_bailinrefund(struct supernet_info *myinfo,struct iguana_info *coin,struct exchange_info *exchange,struct instantdex_accept *A,char *nextcmd,uint8_t secret160[20],cJSON *newjson,int32_t isbob,bits256 A0,bits256 B0,bits256 *sharedprivs) +{ + struct bitcoin_spend *spend; char *bailintx,*refundtx,field[64]; bits256 bailintxid,refundtxid; + if ( bits256_nonz(A0) > 0 && bits256_nonz(B0) > 0 ) + { + if ( (spend= instantdex_spendset(myinfo,coin,A->A.basevolume64,INSTANTDEX_DONATION)) != 0 ) + { + bailintx = instantdex_bailintx(coin,&bailintxid,spend,A0,B0,secret160,0); + refundtx = instantdex_refundtx(coin,&refundtxid,sharedprivs[0],sharedprivs[2],bailintxid,A->A.basevolume64,coin->chain->txfee,isbob); + if ( A->statusjson == 0 ) + A->statusjson = cJSON_CreateObject(); + sprintf(field,"bailin%c",'A'+isbob), jaddstr(A->statusjson,field,bailintx), free(bailintx); + sprintf(field,"refund%c",'A'+isbob), jaddstr(A->statusjson,field,refundtx), free(refundtx); + sprintf(field,"bailintx%c",'A'+isbob), jaddbits256(A->statusjson,field,bailintxid); + sprintf(field,"bailintxid%c",'A'+isbob), jaddbits256(newjson,field,bailintxid); + free(spend); + return(instantdex_sendcmd(myinfo,newjson,nextcmd,myinfo->ipaddr,INSTANTDEX_HOPS)); + } else return(clonestr("{\"error\":\"couldnt create bailintx\"}")); + } else return(clonestr("{\"error\":\"dont have pubkey0 pair\"}")); +} + +cJSON *instantdex_payout(struct supernet_info *myinfo,struct iguana_info *coin,struct exchange_info *exchange,struct instantdex_accept *A,uint8_t secret160[20],int32_t isbob,bits256 *A0p,bits256 *B0p,bits256 *sharedprivs,bits256 hash,uint64_t satoshis[2],cJSON *argjson) +{ + cJSON *newjson; char field[32],payoutsigstr[256],*signedpayout; int32_t payoutsiglen; bits256 payouttxid,bailintxid; + if ( (newjson= instantdex_newjson(myinfo,A0p,B0p,sharedprivs,secret160,isbob,argjson,hash)) == 0 ) + return(0); + sprintf(field,"bailintxid%c",'A' + (isbob^1)), bailintxid = jbits256(argjson,field); + sprintf(field,"payoutsig%c",'A' + (isbob^1)); + if ( (signedpayout= instantdex_payouttx(coin,payoutsigstr,&payoutsiglen,&payouttxid,sharedprivs,bailintxid,satoshis[isbob],coin->chain->txfee,isbob,jstr(argjson,field))) != 0 ) + { + sprintf(field,"payoutsig%c",'A'+isbob), jaddstr(newjson,field,payoutsigstr); + if ( A->statusjson == 0 ) + A->statusjson = cJSON_CreateObject(); + sprintf(field,"payout%c",'A'+isbob), jaddstr(A->statusjson,field,signedpayout); + free(signedpayout); + } + return(newjson); +} + +char *instantdex_advance(struct supernet_info *myinfo,bits256 *sharedprivs,int32_t isbob,cJSON *argjson,bits256 hash,char *addfield,char *nextstate,struct instantdex_accept *A) +{ + cJSON *newjson; bits256 A0,B0; uint8_t secret160[20]; + if ( (newjson= instantdex_newjson(myinfo,&A0,&B0,sharedprivs,secret160,isbob,argjson,hash)) == 0 ) + return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}")); + if ( A->statusjson != 0 && jstr(A->statusjson,addfield) != 0 ) + { + jaddstr(newjson,addfield,jstr(A->statusjson,addfield)); + if ( nextstate != 0 ) + return(instantdex_sendcmd(myinfo,newjson,nextstate,myinfo->ipaddr,INSTANTDEX_HOPS)); + else return(clonestr("{\"result\":\"instantdex_BTCswap advance complete, wait or refund\"}")); + } else return(clonestr("{\"error\":\"instantdex_BTCswap advance cant find statusjson\"}")); +} + char *instantdex_BTCswap(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,char *cmdstr,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,uint8_t *data,int32_t datalen) // receiving side { - uint8_t script[999],p2sh_rmd160[20],secret160[20],pubkey[36],addrtype; - bits256 hash,bailintxid,A0,B0; struct bitcoin_spend SPEND; - struct instantdex_accept *ap; uint64_t satoshis,othersatoshis,orderid; - char p2sh_coinaddr[64],*senderaddr,otheraddr[64],base[24],coinaddr[64],*retstr,*bailintx; - int32_t scriptlen,locktime,offerdir = 0; struct iguana_info *coinbtc,*other; cJSON *newjson; - retstr = 0; - memset(&SPEND,0,sizeof(SPEND)); + uint8_t secret160[20]; bits256 hash,A0,B0,sharedprivs[4]; uint64_t satoshis[2]; cJSON *newjson; + struct instantdex_accept *ap; char *retstr=0,*str; + int32_t locktime,isbob=0,offerdir = 0; struct iguana_info *coinbtc,*other; if ( exchange == 0 ) return(clonestr("{\"error\":\"instantdex_BTCswap null exchange ptr\"}")); offerdir = instantdex_bidaskdir(A); @@ -173,84 +412,69 @@ char *instantdex_BTCswap(struct supernet_info *myinfo,struct exchange_info *exch locktime = (uint32_t)(A->A.expiration + INSTANTDEX_OFFERDURATION); if ( A->A.rel == 0 || strcmp(A->A.rel,"BTC") != 0 ) return(clonestr("{\"error\":\"instantdex_BTCswap offer non BTC rel\"}")); + vcalc_sha256(0,hash.bytes,(void *)&A->A,sizeof(ap->A)); + if ( hash.txid != A->orderid ) + return(clonestr("{\"error\":\"txid mismatches orderid\"}")); + satoshis[0] = A->A.basevolume64; + satoshis[1] = instantdex_relsatoshis(A->A.price64,A->A.basevolume64); + printf("got offer.(%s) offerside.%d offerdir.%d\n",jprint(argjson,0),A->A.myside,A->A.acceptdir); if ( strcmp(cmdstr,"offer") == 0 ) // sender is Bob, receiver is network (Alice) { - // should add to orderbook if not accepted if ( A->A.expiration < (time(NULL) + INSTANTDEX_DURATION) ) return(clonestr("{\"error\":\"instantdex_BTCswap offer too close to expiration\"}")); - printf("got offer.(%s) offerside.%d offerdir.%d\n",jprint(argjson,0),A->A.myside,A->A.acceptdir); if ( (ap= instantdex_acceptable(exchange,A,myinfo->myaddr.nxt64bits)) != 0 ) { - ap->pendingvolume64 -= A->A.basevolume64; - satoshis = instantdex_relsatoshis(A->A.price64,A->A.basevolume64); - newjson = cJSON_CreateObject(); - if ( instantdex_pubkeyargs(argjson,3,myinfo->persistent_priv,hash,0x02) != 3 ) - return(clonestr("{\"error\":\"highly unlikely run of 03 pubkeys\"}")); - jadd64bits(newjson,"id",A->orderid); - jadd64bits(newjson,"BTC",satoshis); - jadd64bits(newjson,"v",A->A.basevolume64); - jaddstr(newjson,"b",other->symbol); - jaddstr(newjson,other->symbol,otheraddr); - jaddstr(newjson,"p2sh",p2sh_coinaddr); - bailintx = instantdex_bailintx(coinbtc,&bailintxid,&SPEND,A0,B0,secret160,1); - jaddstr(newjson,"bailin",bailintx); - jaddbits256(newjson,"bailintxid",bailintxid); - free(bailintx); - return(instantdex_sendcmd(myinfo,newjson,"proposal",myinfo->ipaddr,INSTANTDEX_HOPS)); - } else printf("no matching trade.(%s)\n",jprint(argjson,0)); - } - else if ( strcmp(cmdstr,"proposal") == 0 ) // sender is Alice, receiver is Bob - { - satoshis = j64bits(argjson,"BTC"); - orderid = j64bits(argjson,"id"); - othersatoshis = j64bits(argjson,"v"); - senderaddr = myinfo->myaddr.BTC; - if ( jobj(argjson,other->symbol) != 0 ) - safecopy(otheraddr,jstr(argjson,other->symbol),sizeof(otheraddr)); - if ( jobj(argjson,"b") != 0 ) - safecopy(base,jstr(argjson,"b"),sizeof(base)); - printf("proposal orderid.%llu BTC satoshis %.8f for %s vol %.8f ps2h.%s\n",A->orderid,dstr(satoshis),base,dstr(othersatoshis),p2sh_coinaddr); - if ( A->orderid != orderid ) - { - printf("orderid mismatch %llu vs %llu\n",(long long)orderid,(long long)A->orderid); - return(clonestr("{\"error\":\"instantdex_BTCswap orderid mismatch\"}")); - } - if ( senderaddr == 0 || strcmp(A->A.base,base) != 0 || strcmp(A->A.rel,"BTC") != 0 ) - { - printf("senderaddr.%p base.(%s vs %s) rel.(%s vs %s)\n",senderaddr,A->A.base,base,A->A.rel,"BTC"); - return(clonestr("{\"error\":\"instantdex_BTCswap base or rel mismatch\"}")); - } - bitcoin_pubkey33(pubkey,myinfo->persistent_priv); - bitcoin_address(coinaddr,other->chain->pubtype,pubkey,sizeof(pubkey)); - bitcoin_addr2rmd160(&addrtype,secret160,coinaddr); - scriptlen = bitcoin_cltvscript(coinbtc->chain->p2shtype,p2sh_coinaddr,p2sh_rmd160,script,0,senderaddr,otheraddr,secret160,locktime); - if ( jobj(argjson,"p2sh") != 0 ) - { - if ( strcmp(jstr(argjson,"p2sh"),p2sh_coinaddr) != 0 ) + isbob = 0; + if ( (newjson= instantdex_newjson(myinfo,&A0,&B0,sharedprivs,secret160,isbob,argjson,hash)) == 0 ) + return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}")); + else { - printf("mismatched p2sh.(%s) vs (%s)\n",jstr(argjson,"p2sh"),p2sh_coinaddr); - return(clonestr("{\"error\":\"instantdex_BTCswap base or rel mismatch\"}")); + // should add to orderbook if not accepted + instantdex_pendingnotice(myinfo,exchange,ap,A); + return(instantdex_bailinrefund(myinfo,other,exchange,A,"proposal",secret160,newjson,isbob,A0,B0,sharedprivs)); } } - if ( satoshis != instantdex_relsatoshis(A->A.price64,A->A.basevolume64) ) - { - printf("satoshis mismatch %llu vs %llu\n",(long long)satoshis,(long long)instantdex_relsatoshis(A->A.price64,A->A.basevolume64)); - return(clonestr("{\"error\":\"instantdex_BTCswap satoshis mismatch\"}")); - } - if ( othersatoshis != A->A.basevolume64 ) + else { - printf("othersatoshis mismatch %llu vs %llu\n",(long long)satoshis,(long long)A->A.basevolume64); - return(clonestr("{\"error\":\"instantdex_BTCswap satoshis mismatch\"}")); + printf("no matching trade.(%s)\n",jprint(argjson,0)); + if ( (str= InstantDEX_minaccept(myinfo,0,argjson,0,A->A.base,"BTC",dstr(A->A.price64),dstr(A->A.basevolume64))) != 0 ) + free(str); } - // return(instantdex_sendcmd(myinfo,newjson,"accept",myinfo->ipaddr,INSTANTDEX_HOPS)); } + else if ( strcmp(cmdstr,"proposal") == 0 ) // sender is Alice, receiver is Bob + { + isbob = 1; + newjson = instantdex_payout(myinfo,coinbtc,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson); + return(instantdex_bailinrefund(myinfo,coinbtc,exchange,A,"BTCaccept",secret160,newjson,isbob,A0,B0,sharedprivs)); + } else if ( strcmp(cmdstr,"accept") == 0 ) // sender is Bob, receiver is Alice { - + isbob = 0; + newjson = instantdex_payout(myinfo,other,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson); + return(instantdex_sendcmd(myinfo,newjson,"BTCconfirm",myinfo->ipaddr,INSTANTDEX_HOPS)); + } + else if ( strcmp(cmdstr,"confirm") == 0 ) // sender is Alice, receiver is Bob + { + isbob = 1; + newjson = instantdex_payout(myinfo,coinbtc,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson); + return(instantdex_sendcmd(myinfo,newjson,"BTCbroadcast",myinfo->ipaddr,INSTANTDEX_HOPS)); + } + else if ( strcmp(cmdstr,"broadcast") == 0 ) // sender is Bob, receiver is Alice + { + isbob = 0; + return(instantdex_advance(myinfo,sharedprivs,isbob,argjson,hash,"bailintxA","BTCcommit",A)); + } + else if ( strcmp(cmdstr,"commit") == 0 ) // sender is Alice, receiver is Bob + { + isbob = 1; + // go into refund state, ie watch for payouts to complete or get refund + return(instantdex_advance(myinfo,sharedprivs,isbob,argjson,hash,"payoutB","BTCcomplete",A)); } - else if ( strcmp(cmdstr,"confirm") == 0 ) // both send and receive + else if ( strcmp(cmdstr,"complete") == 0 ) // sender is Bob, receiver is Alice { - + isbob = 0; + // go into refund state, ie watch for payouts to complete or get refund + return(instantdex_advance(myinfo,sharedprivs,isbob,argjson,hash,"payoutA",0,A)); } else retstr = clonestr("{\"error\":\"BTC swap got unrecognized command\"}"); if ( retstr == 0 )