Browse Source

revised FSM

release/v0.1
jl777 9 years ago
parent
commit
883167f7e6
  1. 156
      deprecated/obsolete.h
  2. 1
      iguana/SuperNET.h
  3. 6
      iguana/exchanges/bitcoin.c
  4. 5
      iguana/exchanges777.h
  5. 13
      iguana/iguana_exchanges.c
  6. 18
      iguana/iguana_init.c
  7. 207
      iguana/iguana_instantdex.c
  8. 2
      iguana/main.c
  9. 828
      iguana/swaps/iguana_BTCswap.c
  10. 23
      iguana/swaps/iguana_PAXswap.c
  11. 453
      includes/secp256k1.h
  12. 30
      includes/secp256k1_ecdh.h
  13. 186
      includes/secp256k1_rangeproof.h
  14. 173
      includes/secp256k1_schnorr.h

156
deprecated/obsolete.h

@ -13565,5 +13565,161 @@ len = 0;
swap->minperc = minperc;
return(instantdex_statemachine(myinfo,exchange,A,cmdstr,swap,argjson,serdata,serdatalen,altcoin,coinbtc));
}
#ifdef xxx
if ( strcmp(cmdstr,"step1") == 0 && strcmp(swap->nextstate,cmdstr) == 0 ) // either
{
printf("%s got step1, should have other's choosei\n",swap->isbob!=0?"BOB":"alice");
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,0)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap step1 null newjson\"}"));
else if ( swap->otherschoosei < 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap step1, no didnt choosei\"}"));
else
{
printf("%s chose.%d\n",swap->isbob==0?"BOB":"alice",swap->otherschoosei);
if ( swap->isbob == 0 )
swap->privAm = swap->privkeys[swap->otherschoosei];
else swap->privBn = swap->privkeys[swap->otherschoosei];
memset(&swap->privkeys[swap->otherschoosei],0,sizeof(swap->privkeys[swap->otherschoosei]));
if ( (retstr= instantdex_choosei(swap,newjson,argjson,serdata,serdatalen)) != 0 )
return(retstr);
/*if ( swap->isbob == 0 )
{
if ( (swap->feetx= instantdex_bobtx(myinfo,coinbtc,&swap->ftxid,swap->otherpubs[0],swap->mypubs[0],swap->privkeys[swap->otherschoosei],reftime,swap->insurance,1)) != 0 )
{
jaddstr(newjson,"feetx",swap->feetx);
jaddbits256(newjson,"ftxid",swap->ftxid);
// broadcast to network
}
}*/
if ( swap->isbob != 0 )
{
strcpy(swap->nextstate,"step4");
printf("BOB sends (%s), next.(%s)\n","BTCstep3",swap->nextstate);
}
else
{
strcpy(swap->nextstate,"step3");
printf("Alice sends (%s), next.(%s)\n","BTCstep2",swap->nextstate);
}
return(instantdex_sendcmd(myinfo,&A->offer,newjson,swap->isbob != 0 ? "BTCstep3" : "BTCstep2",swap->othertrader,INSTANTDEX_HOPS,swap->privkeys,sizeof(swap->privkeys)));
}
}
else if ( strcmp(cmdstr,"step2") == 0 && strcmp(swap->nextstate,"cmdstr") == 0 ) // bob
{
printf("%s got step2, should have other's privkeys\n",swap->isbob!=0?"BOB":"alice");
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,0)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap step2 null newjson\"}"));
else
{
instantdex_privkeysextract(myinfo,swap,serdata,serdatalen);
if ( swap->cutverified == 0 || swap->otherverifiedcut == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap step2, both sides didnt validate\"}"));
else
{
if ( (swap->deposit= instantdex_bobtx(myinfo,coinbtc,&swap->dtxid,swap->otherpubs[0],swap->mypubs[0],swap->privkeys[swap->otherschoosei],reftime,swap->satoshis[swap->isbob],1)) != 0 )
{
jaddstr(newjson,"deposit",swap->deposit);
jaddbits256(newjson,"dtxid",swap->dtxid);
//jaddbits256(newjson,"pubBn",bitcoin_pubkey33(pubkey,swap->pubBn));
// broadcast to network
strcpy(swap->nextstate,"step4");
printf("BOB sends (%s), next.(%s)\n","BTCstep3",swap->nextstate);
return(instantdex_sendcmd(myinfo,&A->offer,newjson,"BTCstep3",swap->othertrader,INSTANTDEX_HOPS,0,0));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Bob step2, cant create deposit\"}"));
}
} //else return(clonestr("{\"error\":\"instantdex_BTCswap step2 invalid fee\"}"));
}
else if ( strcmp(cmdstr,"step3") == 0 && strcmp(swap->nextstate,"cmdstr") == 0 ) // alice
{
printf("Alice got step3 should have Bob's choosei\n");
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,0)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap Alice step3 null newjson\"}"));
else
{
instantdex_privkeysextract(myinfo,swap,serdata,serdatalen);
if ( swap->cutverified == 0 || swap->otherverifiedcut == 0 || bits256_nonz(swap->pubBn) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap step3, both sides didnt validate\"}"));
else if ( instantdex_paymentverify(myinfo,coinbtc,swap,A,argjson,1) == 0 )
{
//swap->pubAm = bitcoin_pubkey33(pubkey,swap->privkeys[swap->otherschoosei]);
if ( (swap->altpayment= instantdex_alicetx(myinfo,altcoin,swap->altmsigaddr,&swap->aptxid,swap->pubAm,swap->pubBn,swap->satoshis[swap->isbob])) != 0 )
{
jaddstr(newjson,"altpayment",swap->altpayment);
jaddstr(newjson,"altmsigaddr",swap->altmsigaddr);
jaddbits256(newjson,"aptxid",swap->aptxid);
jaddbits256(newjson,"pubAm",swap->pubAm);
// broadcast to network
strcpy(swap->nextstate,"step5");
printf("Alice sends (%s), next.(%s)\n","BTCstep4",swap->nextstate);
return(instantdex_sendcmd(myinfo,&A->offer,newjson,"BTCstep4",swap->othertrader,INSTANTDEX_HOPS,0,0));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Alice step3, error making altpay\"}"));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Alice step3, invalid deposit\"}"));
}
}
else if ( strcmp(cmdstr,"step4") == 0 && strcmp(swap->nextstate,"cmdstr") == 0 ) // bob
{
printf("Bob got step4 should have Alice's altpayment\n");
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,0)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap Bob step4 null newjson\"}"));
else if ( bits256_nonz(swap->pubAm) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap step4, no pubAm\"}"));
else if ( instantdex_altpaymentverify(myinfo,altcoin,swap,A,argjson) == 0 )
{
if ( (swap->deposit= instantdex_bobtx(myinfo,coinbtc,&swap->ptxid,swap->mypubs[1],swap->otherpubs[0],swap->privkeys[swap->otherschoosei],reftime,swap->satoshis[swap->isbob],0)) != 0 )
{
jaddstr(newjson,"payment",swap->payment);
jaddbits256(newjson,"ptxid",swap->ptxid);
// broadcast to network
strcpy(swap->nextstate,"step6");
return(instantdex_sendcmd(myinfo,&A->offer,newjson,"BTCstep5",swap->othertrader,INSTANTDEX_HOPS,0,0));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Bob step4, cant create payment\"}"));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Alice step3, invalid deposit\"}"));
}
else if ( strcmp(cmdstr,"step5") == 0 && strcmp(swap->nextstate,"cmdstr") == 0 ) // alice
{
printf("Alice got step5 should have Bob's payment\n");
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,0)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap Alice step5 null newjson\"}"));
else if ( instantdex_paymentverify(myinfo,coinbtc,swap,A,argjson,0) == 0 )
{
strcpy(swap->nextstate,"step7");
/*if ( (swap->spendtx= instantdex_spendpayment(myinfo,coinbtc,&swap->stxid,swap,argjson,newjson)) != 0 )
{
// broadcast to network
return(instantdex_sendcmd(myinfo,&A->A,newjson,"BTCstep6",swap->othertrader,INSTANTDEX_HOPS));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Alice step5, cant spend payment\"}"));*/
} else return(clonestr("{\"error\":\"instantdex_BTCswap Bob step6, invalid payment\"}"));
}
else if ( strcmp(cmdstr,"step6") == 0 && strcmp(swap->nextstate,"cmdstr") == 0 ) // bob
{
printf("Bob got step6 should have Alice's privkey\n");
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,0)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap Bob step6 null newjson\"}"));
strcpy(swap->nextstate,"step7");
/*else if ( instantdex_spendverify(myinfo,coinbtc,swap,A,argjson,0) == 0 )
{
if ( (swap->altspend= instantdex_spendaltpayment(myinfo,altcoin,&swap->astxid,swap,argjson,newjson)) != 0 )
{
jaddstr(newjson,"altspend",swap->altspend);
jaddbits256(newjson,"astxid",swap->astxid);
// broadcast to network
return(clonestr("{\"result\":\"Bob finished atomic swap\"}"));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Bob step6, cant spend altpayment\"}"));
} else return(clonestr("{\"error\":\"instantdex_BTCswap Bob step6, invalid spend\"}"));*/
}
else if ( strcmp(cmdstr,"step7") == 0 && strcmp(swap->nextstate,"cmdstr") == 0 ) // both
{
// update status, goto refund if thresholds exceeded
retstr = clonestr("{\"result\":\"BTC swap updated state\"}");
}
else retstr = clonestr("{\"error\":\"BTC swap got unrecognized command\"}");
if ( retstr == 0 )
retstr = clonestr("{\"error\":\"BTC swap null retstr\"}");
if ( swap != 0 )
printf("BTCSWAP next.(%s) (%s) isbob.%d nextstate.%s verified.(%d %d)\n",swap->nextstate,cmdstr,swap->isbob,swap->nextstate,swap->cutverified,swap->otherverifiedcut);
else printf("BTCSWAP.(%s)\n",retstr);
return(retstr);
#endif
#endif

1
iguana/SuperNET.h

@ -165,6 +165,7 @@ void category_posthexmsg(struct supernet_info *myinfo,bits256 categoryhash,bits2
void *category_subscribe(struct supernet_info *myinfo,bits256 category,bits256 subhash);
struct category_msg *category_gethexmsg(struct supernet_info *myinfo,bits256 categoryhash,bits256 subhash);
char *SuperNET_htmlstr(char *fname,char *htmlstr,int32_t maxsize,char *agentstr);
queue_t *category_Q(bits256 categoryhash,bits256 subhash);
char *SuperNET_categorymulticast(struct supernet_info *myinfo,int32_t surveyflag,bits256 categoryhash,bits256 subhash,char *message,int32_t maxdelay,int32_t broadcastflag,int32_t plaintext,cJSON *argjson,char *remoteaddr);
bits256 calc_categoryhashes(bits256 *subhashp,char *category,char *subcategory);

6
iguana/exchanges/bitcoin.c

@ -1541,15 +1541,15 @@ uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,cha
jaddnum(json,"volume",volume);
jaddstr(json,"BTC",myinfo->myaddr.BTC);
//printf("trade dir.%d (%s/%s) %.6f vol %.8f\n",dir,base,"BTC",price,volume);
if ( (str= instantdex_queueaccept(myinfo,&ap,exchange,base,"BTC",price,volume,-dir,dir > 0 ? "BTC" : base,INSTANTDEX_OFFERDURATION,myinfo->myaddr.nxt64bits,0)) != 0 )
if ( (str= instantdex_queueaccept(myinfo,&ap,exchange,base,"BTC",price,volume,-dir,dir > 0 ? "BTC" : base,INSTANTDEX_OFFERDURATION,myinfo->myaddr.nxt64bits,0)) != 0 && ap != 0 )
{
if ( (tmp= cJSON_Parse(str)) != 0 )
{
txid = j64bits(json,"orderid");
if ( (str= instantdex_btcoffer(myinfo,exchange,ap,json)) != 0 )
if ( (str= instantdex_sendoffer(myinfo,exchange,ap,json)) != 0 ) // adds to statemachine
{
json = cJSON_CreateObject();
jaddstr(json,"BTCoffer",str);
jaddstr(json,"BTCoffer",instantdex_selectqueue(exchange,ap,str));
} else printf("null return from btcoffer\n");
free_json(tmp);
} else printf("queueaccept return parse error.(%s)\n",str);

5
iguana/exchanges777.h

@ -52,7 +52,7 @@ struct exchange_info
uint32_t exchangeid,pollgap,lastpoll;
uint64_t lastnonce,exchangebits; double commission;
void *privatedata;
CURL *cHandle; queue_t requestQ,pricesQ,pendingQ,tradebotsQ,acceptableQ;
CURL *cHandle; queue_t requestQ,pricesQ,statemachineQ,tradebotsQ,acceptableQ;
};
struct instantdex_msghdr
@ -120,6 +120,7 @@ double instaforex_price(struct exchange_info *exchange,char *base,char *rel,stru
char *instantdex_queueaccept(struct supernet_info *myinfo,struct instantdex_accept **aptrp,struct exchange_info *exchange,char *base,char *rel,double price,double basevolume,int32_t acceptdir,char *mysidestr,int32_t duration,uint64_t txid,int32_t queueflag);
void instantdex_update(struct supernet_info *myinfo);
char *instantdex_sendcmd(struct supernet_info *myinfo,struct instantdex_offer *offer,cJSON *argjson,char *cmdstr,bits256 desthash,int32_t hops,void *extra,int32_t extralen);
char *instantdex_btcoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap,cJSON *argjson); // Bob sending to network (Alice)
char *instantdex_sendoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap,cJSON *argjson); // Bob sending to network (Alice)
char *instantdex_selectqueue(struct exchange_info *exchange,struct instantdex_accept *ap,char *retstr);
#endif

13
iguana/iguana_exchanges.c

@ -660,7 +660,7 @@ void exchanges777_loop(void *ptr)
{
if ( strcmp(exchange->name,"bitcoin") == 0 )
{
//instantdex_update(SuperNET_MYINFO(0));
instantdex_update(SuperNET_MYINFO(0));
//printf("InstantDEX call update\n");
}
if ( (req= queue_dequeue(&exchange->pricesQ,0)) != 0 )
@ -890,7 +890,7 @@ struct exchange_info *exchange_create(char *exchangestr,cJSON *argjson)
iguana_initQ(&exchange->requestQ,"request");
iguana_initQ(&exchange->acceptableQ,"acceptable");
iguana_initQ(&exchange->tradebotsQ,"tradebots");
iguana_initQ(&exchange->pendingQ,"pending");
iguana_initQ(&exchange->statemachineQ,"statemachineQ");
exchange->exchangeid = exchangeid;
safecopy(exchange->name,exchangestr,sizeof(exchange->name));
exchange->exchangebits = stringbits(exchange->name);
@ -967,7 +967,6 @@ THREE_STRINGS_AND_THREE_INTS(InstantDEX,orderbook,exchange,base,rel,depth,allfie
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qprices(ptr,base,rel,juint(json,"maxseconds"),allfields,depth,json,0,ptr->commission));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -979,7 +978,6 @@ THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,buy,exchange,base,rel,price,volume,do
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qtrade(ptr,base,rel,juint(json,"maxseconds"),dotrade,1,price,volume,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -991,7 +989,6 @@ THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,sell,exchange,base,rel,price,volume,d
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qtrade(ptr,base,rel,juint(json,"maxseconds"),dotrade,-1,price,volume,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -1003,7 +1000,6 @@ THREE_STRINGS_AND_DOUBLE(InstantDEX,withdraw,exchange,base,destaddr,amount)
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qrequest(ptr,'W',base,0,juint(json,"maxseconds"),0,destaddr,amount,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -1015,7 +1011,6 @@ TWO_STRINGS(InstantDEX,balance,exchange,base)
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qrequest(ptr,'B',base,0,juint(json,"maxseconds"),0,0,0,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -1027,7 +1022,6 @@ TWO_STRINGS(InstantDEX,orderstatus,exchange,orderid)
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qrequest(ptr,'P',0,0,juint(json,"maxseconds"),calc_nxt64bits(orderid),0,0,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -1039,7 +1033,6 @@ TWO_STRINGS(InstantDEX,cancelorder,exchange,orderid)
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qrequest(ptr,'C',0,0,juint(json,"maxseconds"),calc_nxt64bits(orderid),0,0,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -1051,7 +1044,6 @@ STRING_ARG(InstantDEX,openorders,exchange)
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qrequest(ptr,'O',0,0,juint(json,"maxseconds"),0,0,0,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
@ -1063,7 +1055,6 @@ STRING_ARG(InstantDEX,tradehistory,exchange)
struct exchange_info *ptr;
if ( remoteaddr == 0 )
{
//instantdex_update(myinfo);
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
return(exchanges777_Qrequest(ptr,'H',0,0,juint(json,"maxseconds"),0,0,0,json));
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));

18
iguana/iguana_init.c

@ -252,7 +252,7 @@ void iguana_parseline(struct iguana_info *coin,int32_t iter,FILE *fp)
if ( strcmp(checkstr,line+k+1 + 64 + 1) == 0 )
{
init_hexbytes_noT(checkstr,hash2.bytes,sizeof(hash2));
//char str[65],str2[65]; printf(">>>> bundle.%d got (%s)/(%s) allhash.(%s)\n",height,bits256_str(str,hash2),checkstr,bits256_str(str2,allhash));
char str[65],str2[65]; printf(">>>> bundle.%d got (%s)/(%s) allhash.(%s)\n",height,bits256_str(str,hash2),checkstr,bits256_str(str2,allhash));
if ( (bp= iguana_bundlecreate(coin,&bundlei,height,hash2,allhash,0)) != 0 )
{
bp->bundleheight = height;
@ -275,22 +275,6 @@ void iguana_parseline(struct iguana_info *coin,int32_t iter,FILE *fp)
}
}
}
/*init_hexbytes_noT(checkstr,hash2.bytes,sizeof(hash2));
if ( strncmp(checkstr,line+k+1,64) == 0 )
{
if ( (height % coin->chain->bundlesize) == 1 )
{
if ( (bp= coin->bundles[height/coin->chain->bundlesize]) != 0 )
{
if ( iguana_bundlehash2add(coin,0,bp,1,hash2) == 0 )
{
//printf("add bundle.%d:%d (%s)\n",bundleheight,bp->hdrsi,bits256_str(str,hash2));
if ( (block= iguana_blockfind(coin,hash2)) != 0 )
block->mainchain = 1, block->height = bundleheight+1;
}
}
}
}*/
}
}
}

207
iguana/iguana_instantdex.c

@ -33,8 +33,8 @@ struct instantdex_event { char cmdstr[24],sendcmd[16]; struct instantdex_statein
struct instantdex_stateinfo
{
char name[24];
cJSON *(*process)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,uint8_t **serdatap,int32_t *serdatalenp);
cJSON *(*timeout)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,uint8_t **serdatap,int32_t *serdatalenp);
cJSON *(*process)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp);
cJSON *(*timeout)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp);
struct instantdex_stateinfo *timeoutevent,*errorevent;
struct instantdex_event *events; int32_t numevents;
};
@ -42,18 +42,37 @@ struct instantdex_stateinfo
struct bitcoin_swapinfo
{
bits256 privkeys[777],mypubs[2],otherpubs[2],privAm,pubAm,privBn,pubBn;
bits256 orderhash,dtxid,ptxid,aptxid,astxid,stxid,ftxid,othertrader;
bits256 orderhash,deposittxid,paymenttxid,altpaymenttxid,myfeetxid,otherfeetxid,othertrader;
uint64_t otherscut[777][2],deck[777][2],satoshis[2],insurance,bidid,askid;
int32_t isbob,choosei,otherschoosei,cutverified,otherverifiedcut;
double minperc;
char altmsigaddr[64],*deposit,*payment,*altpayment,*altspend,*spendtx,*feetx;
char altmsigaddr[64],expectedcmdstr[16],*deposit,*payment,*altpayment,*myfeetx,*otherfeetx;
double minperc,depositconfirms,paymentconfirms,altpaymentconfirms,myfeeconfirms,otherfeeconfirms;
struct instantdex_stateinfo *state; uint32_t expiration;
};
struct instantdex_stateinfo *BTC_states; int32_t BTC_numstates;
cJSON *instantdex_defaultprocess(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,uint8_t **serdatap,int32_t *serdatalenp)
void instantdex_swapfree(struct instantdex_accept *A,struct bitcoin_swapinfo *swap)
{
cJSON *newjson=0; uint8_t *serdata = *serdatap; int32_t serdatalen = *serdatalenp;
if ( A != 0 )
free(A);
if ( swap != 0 )
{
if ( swap->deposit != 0 )
free(swap->deposit);
if ( swap->payment != 0 )
free(swap->payment);
if ( swap->altpayment != 0 )
free(swap->altpayment);
if ( swap->myfeetx != 0 )
free(swap->myfeetx);
if ( swap->otherfeetx != 0 )
free(swap->otherfeetx);
}
}
cJSON *instantdex_defaultprocess(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
uint8_t *serdata = *serdatap; int32_t serdatalen = *serdatalenp;
*serdatap = 0, *serdatalenp = 0;
if ( serdata != 0 && serdatalen > 0 )
{
@ -62,9 +81,9 @@ cJSON *instantdex_defaultprocess(struct supernet_info *myinfo,struct exchange_in
return(newjson);
}
cJSON *instantdex_defaulttimeout(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,uint8_t **serdatap,int32_t *serdatalenp)
cJSON *instantdex_defaulttimeout(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
cJSON *newjson=0; uint8_t *serdata = *serdatap; int32_t serdatalen = *serdatalenp;
uint8_t *serdata = *serdatap; int32_t serdatalen = *serdatalenp;
*serdatap = 0, *serdatalenp = 0;
if ( serdata != 0 && serdatalen > 0 )
{
@ -90,7 +109,7 @@ struct instantdex_stateinfo *instantdex_statefind(struct instantdex_stateinfo *s
return(0);
}
struct instantdex_stateinfo *instantdex_statecreate(struct instantdex_stateinfo *states,int32_t *numstatesp,char *name,cJSON *(*process_func)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,uint8_t **serdatap,int32_t *serdatalenp),cJSON *(*timeout_func)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,uint8_t **serdatap,int32_t *serdatalenp),char *timeoutstr,char *errorstr)
struct instantdex_stateinfo *instantdex_statecreate(struct instantdex_stateinfo *states,int32_t *numstatesp,char *name,cJSON *(*process_func)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp),cJSON *(*timeout_func)(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp),char *timeoutstr,char *errorstr)
{
struct instantdex_stateinfo *timeoutstate,*errorstate,*state = 0;
if ( (state= instantdex_statefind(states,*numstatesp,name)) == 0 )
@ -433,13 +452,13 @@ cJSON *instantdex_acceptjson(struct instantdex_accept *ap)
return(item);
}
struct instantdex_accept *instantdex_pendingfind(struct supernet_info *myinfo,struct exchange_info *exchange,uint64_t orderid)
struct instantdex_accept *instantdex_statemachinefind(struct supernet_info *myinfo,struct exchange_info *exchange,uint64_t orderid)
{
struct instantdex_accept PAD,*ap,*retap = 0; uint32_t now;
now = (uint32_t)time(NULL);
memset(&PAD,0,sizeof(PAD));
queue_enqueue("pendingQ",&exchange->pendingQ,&PAD.DL,0);
while ( (ap= queue_dequeue(&exchange->pendingQ,0)) != 0 && ap != &PAD )
queue_enqueue("statemachineQ",&exchange->statemachineQ,&PAD.DL,0);
while ( (ap= queue_dequeue(&exchange->statemachineQ,0)) != 0 && ap != &PAD )
{
if ( now < ap->offer.expiration && ap->dead == 0 )
{
@ -450,7 +469,7 @@ struct instantdex_accept *instantdex_pendingfind(struct supernet_info *myinfo,st
{
printf("expired pending, need to take action\n");
}
queue_enqueue("pendingQ",&exchange->pendingQ,&PAD.DL,0);
queue_enqueue("statemachineQ",&exchange->statemachineQ,&PAD.DL,0);
}
return(retap);
}
@ -525,7 +544,7 @@ struct instantdex_accept *instantdex_acceptable(struct supernet_info *myinfo,str
}
}
}
if ( ap != retap)
if ( ap != retap )
queue_enqueue("acceptableQ",&exchange->acceptableQ,&ap->DL,0);
} else free(ap);
}
@ -631,7 +650,7 @@ char *instantdex_swapset(struct supernet_info *myinfo,struct instantdex_accept *
struct bitcoin_swapinfo *swap; bits256 orderhash,traderpub; struct iguana_info *coinbtc;
if ( (swap= A->info) == 0 )
return(clonestr("{\"error\":\"no swapinfo set\"}"));
relsatoshis = instantdex_relsatoshis(A->offer.price64,A->offer.basevolume64);
relsatoshis = instantdex_BTCsatoshis(A->offer.price64,A->offer.basevolume64);
traderpub = jbits256(argjson,"traderpub");
if ( (minperc= jdouble(argjson,"p")) < INSTANTDEX_MINPERC )
minperc = INSTANTDEX_MINPERC;
@ -665,48 +684,50 @@ char *instantdex_swapset(struct supernet_info *myinfo,struct instantdex_accept *
return(0);
}
char *instantdex_btcoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,cJSON *argjson) // Bob sending to network (Alice)
char *instantdex_addfeetx(struct supernet_info *myinfo,cJSON *newjson,struct instantdex_accept *ap,struct bitcoin_swapinfo *swap,char *bobstate,char *alicestate)
{
struct iguana_info *other; struct bitcoin_swapinfo *swap; int32_t isbob; cJSON *newjson; char *retstr;
if ( strcmp(A->offer.rel,"BTC") != 0 )
if ( (swap->myfeetx= instantdex_feetx(myinfo,&swap->myfeetxid,ap)) != 0 )
{
printf("rel not BTC?!\n");
return(clonestr("{\"error\":\"invalid othercoin\"}"));
jaddstr(newjson,"feetx",swap->myfeetx);
jaddbits256(newjson,"feetxid",swap->myfeetxid);
swap->state = instantdex_statefind(BTC_states,BTC_numstates,swap->isbob != 0 ? bobstate : alicestate);
return(0);
}
else if ( (other= iguana_coinfind(A->offer.base)) == 0 )
return(clonestr("{\"error\":\"couldnt create feetx\"}"));
}
char *instantdex_sendoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap,cJSON *argjson) // Bob sending to network (Alice)
{
struct iguana_info *other; struct bitcoin_swapinfo *swap; int32_t isbob; cJSON *newjson; char *retstr;
if ( strcmp(ap->offer.rel,"BTC") != 0 )
return(clonestr("{\"error\":\"invalid othercoin\"}"));
else if ( A->offer.price64 <= 0 || A->offer.basevolume64 <= 0 )
{
printf("illegal price %.8f or volume %.8f\n",dstr(A->offer.price64),dstr(A->offer.basevolume64));
else if ( (other= iguana_coinfind(ap->offer.base)) == 0 )
return(clonestr("{\"error\":\"invalid othercoin\"}"));
else if ( ap->offer.price64 <= 0 || ap->offer.basevolume64 <= 0 )
return(clonestr("{\"error\":\"illegal price or volume\"}"));
}
isbob = (A->offer.myside == 1);
swap = calloc(1,sizeof(struct bitcoin_swapinfo)), swap->isbob = isbob, swap->choosei = swap->otherschoosei = -1;
A->info = swap;
if ( (retstr= instantdex_swapset(myinfo,A,argjson)) != 0 )
isbob = (ap->offer.myside == 1);
swap = calloc(1,sizeof(struct bitcoin_swapinfo));
swap->isbob = isbob;
swap->expiration = (uint32_t)(time(NULL) + INSTANTDEX_LOCKTIME*isbob);
swap->choosei = swap->otherschoosei = -1;
swap->depositconfirms = swap->paymentconfirms = swap->altpaymentconfirms = swap->myfeeconfirms = swap->otherfeeconfirms = -1;
ap->info = swap;
if ( (retstr= instantdex_swapset(myinfo,ap,argjson)) != 0 )
return(retstr);
A->orderid = swap->orderhash.txid;
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,swap->orderhash,A,1)) == 0 )
ap->orderid = swap->orderhash.txid;
if ( (newjson= instantdex_parseargjson(myinfo,exchange,ap,argjson,1)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}"));
if ( instantdex_pubkeyargs(swap,newjson,777+2,myinfo->persistent_priv,swap->orderhash,0x02+isbob) != 777+2 )
{
printf("error from pubkeyargs\n");
free(swap), free(A);
return(clonestr("{\"error\":\"highly unlikely run of 02 pubkeys\"}"));
}
else
else if ( (retstr= instantdex_addfeetx(myinfo,newjson,ap,swap,"BOB_sentoffer","ALICE_sentoffer")) == 0 )
{
queue_enqueue("pendingQ",&exchange->pendingQ,&A->DL,0);
swap->state = instantdex_statefind(BTC_states,BTC_numstates,swap->isbob != 0 ? "BOB_sentoffer" : "ALICE_sentoffer");
return(instantdex_sendcmd(myinfo,&A->offer,newjson,"BTCoffer",GENESIS_PUBKEY,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck)));
return(instantdex_sendcmd(myinfo,&ap->offer,newjson,"BTCoffer",GENESIS_PUBKEY,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck)));
}
else return(retstr);
}
char *instantdex_gotoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,uint8_t *serdata,int32_t serdatalen) // receiving side
char *instantdex_gotoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,uint8_t *serdata,int32_t serdatalen) // receiving side
{
struct bitcoin_swapinfo *swap = 0; bits256 orderhash,traderpub;
struct iguana_info *coinbtc,*altcoin; cJSON *newjson=0; char *retstr=0;
swap = A->info;
struct bitcoin_swapinfo *swap = 0; bits256 traderpub; struct iguana_info *coinbtc,*altcoin; cJSON *newjson=0; char *retstr=0;
swap = ap->info;
coinbtc = iguana_coinfind("BTC");
traderpub = jbits256(argjson,"traderpub");
if ( bits256_cmp(traderpub,myinfo->myaddr.persistent) == 0 )
@ -714,53 +735,64 @@ char *instantdex_gotoffer(struct supernet_info *myinfo,struct exchange_info *exc
printf("got my own packet\n");
return(clonestr("{\"result\":\"got my own packet\"}"));
}
printf("T.%d got (%s/%s) %.8f vol %.8f %llu offerside.%d offerdir.%d swap.%p decksize.%ld/datalen.%d\n",bits256_cmp(traderpub,myinfo->myaddr.persistent),A->offer.base,A->offer.rel,dstr(A->offer.price64),dstr(A->offer.basevolume64),(long long)A->orderid,A->offer.myside,A->offer.acceptdir,A->info,sizeof(swap->deck),serdatalen);
printf("T.%d got (%s/%s) %.8f vol %.8f %llu offerside.%d offerdir.%d swap.%p decksize.%ld/datalen.%d\n",bits256_cmp(traderpub,myinfo->myaddr.persistent),ap->offer.base,ap->offer.rel,dstr(ap->offer.price64),dstr(ap->offer.basevolume64),(long long)ap->orderid,ap->offer.myside,ap->offer.acceptdir,ap->info,sizeof(swap->deck),serdatalen);
if ( exchange == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap null exchange ptr\"}"));
if ( (altcoin= iguana_coinfind(A->offer.base)) == 0 || coinbtc == 0 )
{
printf("other.%p coinbtc.%p (%s/%s)\n",altcoin,coinbtc,A->offer.base,A->offer.rel);
if ( (altcoin= iguana_coinfind(ap->offer.base)) == 0 || coinbtc == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap cant find btc or other coin info\"}"));
}
if ( strcmp(A->offer.rel,"BTC") != 0 )
if ( strcmp(ap->offer.rel,"BTC") != 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap offer non BTC rel\"}"));
if ( A->offer.expiration < (time(NULL) + INSTANTDEX_DURATION) )
if ( ap->offer.expiration < (time(NULL) + INSTANTDEX_DURATION) )
return(clonestr("{\"error\":\"instantdex_BTCswap offer too close to expiration\"}"));
if ( A->info == 0 )
if ( ap->info == 0 )
{
A->info = swap = calloc(1,sizeof(struct bitcoin_swapinfo));
ap->info = swap = calloc(1,sizeof(struct bitcoin_swapinfo));
swap->choosei = swap->otherschoosei = -1;
swap->isbob = (A->offer.myside ^ 1);
if ( (retstr= instantdex_swapset(myinfo,A,argjson)) != 0 )
swap->depositconfirms = swap->paymentconfirms = swap->altpaymentconfirms = swap->myfeeconfirms = swap->otherfeeconfirms = -1;
swap->isbob = (ap->offer.myside ^ 1);
if ( (retstr= instantdex_swapset(myinfo,ap,argjson)) != 0 )
return(retstr);
if ( instantdex_pubkeyargs(swap,newjson,2+777,myinfo->persistent_priv,swap->orderhash,0x02 + swap->isbob) != 2+777 )
{
printf("error generating pubkeyargs\n");
return(0);
}
char str[65]; printf("GOT OFFER! %p (%s/%s) other.%s myside.%d\n",A->info,A->offer.base,A->offer.rel,bits256_str(str,traderpub),swap->isbob);
if ( (newjson= instantdex_newjson(myinfo,swap,argjson,orderhash,A,1)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap error creating pubkeyargs\"}"));
char str[65]; printf("GOT OFFER! %p (%s/%s) other.%s myside.%d\n",ap->info,ap->offer.base,ap->offer.rel,bits256_str(str,traderpub),swap->isbob);
if ( (newjson= instantdex_parseargjson(myinfo,exchange,ap,argjson,1)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}"));
else
else if ( (retstr= instantdex_addfeetx(myinfo,newjson,ap,swap,"BOB_gotoffer","ALICE_gotoffer")) == 0 )
{
// verify feetx
instantdex_pendingnotice(myinfo,exchange,A,A->offer.basevolume64);
//instantdex_pendingnotice(myinfo,exchange,A,ap->offer.basevolume64);
if ( (retstr= instantdex_choosei(swap,newjson,argjson,serdata,serdatalen)) != 0 )
return(retstr);
else
{
// generate feetx to send
swap->state = instantdex_statefind(BTC_states,BTC_numstates,swap->isbob != 0 ? "BOB_gotoffer" : "ALICE_gotoffer");
return(instantdex_sendcmd(myinfo,&A->offer,newjson,"BTCchose",traderpub,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck)));
return(instantdex_sendcmd(myinfo,&ap->offer,newjson,"BTCchose",traderpub,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck)));
}
}
} else return(retstr);
} else return(clonestr("{\"error\":\"couldnt allocate swap info\"}"));
}
char *instantdex_selectqueue(struct exchange_info *exchange,struct instantdex_accept *ap,char *retstr)
{
cJSON *retjson; int32_t flag = 0;
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( jobj(retjson,"error") != 0 )
{
printf("requeue gotoffer error.(%s)\n",jprint(retjson,0));
instantdex_swapfree(0,ap->info);
ap->info = 0;
flag++;
queue_enqueue("acceptableQ",&exchange->acceptableQ,&ap->DL,0);
}
free_json(retjson);
}
if ( flag == 0 )
queue_enqueue("statemachineQ",&exchange->statemachineQ,&ap->DL,0);
return(retstr);
}
char *instantdex_parse(struct supernet_info *myinfo,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,struct instantdex_offer *offer,bits256 orderhash,uint8_t *serdata,int32_t serdatalen)
{
char cmdstr[16]; struct exchange_info *exchange; double minperc;
struct instantdex_accept A,*ap = 0; bits256 traderpub;
char cmdstr[16],*retstr; struct exchange_info *exchange; double minperc; struct instantdex_accept A,*ap = 0; bits256 traderpub; cJSON *newjson;
if ( BTC_states == 0 )
BTC_states = BTC_initFSM(&BTC_numstates);
exchange = exchanges777_find("bitcoin");
@ -782,7 +814,8 @@ char *instantdex_parse(struct supernet_info *myinfo,struct instantdex_msghdr *ms
minperc = INSTANTDEX_MINPERC;
if ( (ap= instantdex_acceptable(myinfo,exchange,&A,acct777_nxt64bits(traderpub),minperc)) != 0 )
{
return(instantdex_gotoffer(myinfo,exchange,ap,msg,argjson,remoteaddr,signerbits,serdata,serdatalen));
if ( (retstr= instantdex_gotoffer(myinfo,exchange,ap,msg,argjson,remoteaddr,signerbits,serdata,serdatalen)) != 0 ) // adds to statemachine if no error
return(instantdex_selectqueue(exchange,ap,retstr));
}
else
{
@ -796,14 +829,15 @@ char *instantdex_parse(struct supernet_info *myinfo,struct instantdex_msghdr *ms
} else return(clonestr("{\"result\":\"order was already in orderbook\"}"));
}
}
else if ( (ap= instantdex_pendingfind(myinfo,exchange,A.orderid)) != 0 )
else if ( (ap= instantdex_statemachinefind(myinfo,exchange,A.orderid)) != 0 )
{
if ( ap->info == 0 )
{
printf("null swap for orderid.%llu\n",(long long)ap->orderid);
return(clonestr("{\"error\":\"no swap for orderid\"}"));
}
return(instantdex_statemachine(myinfo,exchange,ap,cmdstr,argjson,serdata,serdatalen));
newjson = instantdex_parseargjson(myinfo,exchange,ap,argjson,0);
return(instantdex_statemachine(myinfo,exchange,ap,cmdstr,argjson,newjson,serdata,serdatalen));
}
else
{
@ -917,8 +951,27 @@ char *instantdex_queueaccept(struct supernet_info *myinfo,struct instantdex_acce
void instantdex_update(struct supernet_info *myinfo)
{
struct instantdex_msghdr *pm; struct category_msg *m; int32_t iter; bits256 instantdexhash; char *str,remote[64];
struct instantdex_msghdr *pm; struct category_msg *m; bits256 instantdexhash; char *str,remote[64]; queue_t *Q; struct queueitem *item;
instantdexhash = calc_categoryhashes(0,"InstantDEX",0);
//char str[65]; printf("getmsg.(%s) %llx\n",bits256_str(str,categoryhash),(long long)subhash.txid);
if ( (Q= category_Q(instantdexhash,myinfo->myaddr.persistent)) != 0 && queue_size(Q) > 0 && (item= Q->list) != 0 )
{
m = (void *)item;
if ( m->remoteipbits == 0 && (m= queue_dequeue(Q,0)) )
{
if ( (void *)m == (void *)item )
{
pm = (struct instantdex_msghdr *)m->msg;
if ( m->remoteipbits != 0 )
expand_ipbits(remote,m->remoteipbits);
else remote[0] = 0;
if ( (str= InstantDEX_hexmsg(myinfo,pm,m->len,remote)) != 0 )
free(str);
} else printf("instantdex_update: unexpected m.%p changed item.%p\n",m,item);
free(m);
}
}
/*
for (iter=0; iter<2; iter++)
{
while ( (m= category_gethexmsg(myinfo,instantdexhash,iter == 0 ? GENESIS_PUBKEY : myinfo->myaddr.persistent)) != 0 )
@ -932,7 +985,7 @@ void instantdex_update(struct supernet_info *myinfo)
free(str);
free(m);
}
}
}*/
}
#include "../includes/iguana_apidefs.h"

2
iguana/main.c

@ -1035,7 +1035,7 @@ void iguana_main(void *arg)
mycalloc(0,0,0);
myinfo = SuperNET_MYINFO(0);
FILE *fp; int32_t iter;
FILE *fp; int32_t iter; void ztest(); ztest();
strcpy(myinfo->NXTAPIURL,"http://127.0.0.1:7876/nxt");
for (iter=0; iter<2; iter++)
{

828
iguana/swaps/iguana_BTCswap.c

File diff suppressed because it is too large

23
iguana/swaps/iguana_PAXswap.c

@ -47,3 +47,26 @@ char *instantdex_PAXswap(struct supernet_info *myinfo,struct exchange_info *exch
else retstr = clonestr("{\"error\":\"PAX swap got unrecognized command\"}");
return(retstr);
}
#include "../../includes/secp256k1.h"
//#include "../../crypto777/secp256k1/modules/rangeproof/pedersen_impl.h"
//#include "../../crypto777/secp256k1/modules/rangeproof/borromean_impl.h"
//#include "../../crypto777/secp256k1/modules/rangeproof/rangeproof_impl.h"
void secp256k1_pedersen_context_initialize(secp256k1_context_t *ctx);
int secp256k1_pedersen_commit(const secp256k1_context_t* ctx, unsigned char *commit, unsigned char *blind, uint64_t value);
// ./configure --enable-module-ecdh --enable-module-schnorr --enable-module-rangeproof
void ztest()
{
#ifdef __APPLE__
printf("ztests\n");
secp256k1_context_t *ctx; uint8_t commit[33],blind[32]; int32_t i,retval;
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_pedersen_context_initialize(ctx);
retval = secp256k1_pedersen_commit(ctx,commit,blind,0x14234);
OS_randombytes(blind,sizeof(blind));
for (i=0; i<33; i++)
printf("%02x",commit[i]);
printf(" pederson commit.%d\n",retval);
//getchar();
#endif
}

453
includes/secp256k1.h

@ -0,0 +1,453 @@
#ifndef _SECP256K1_
# define _SECP256K1_
# ifdef __cplusplus
extern "C" {
# endif
# if !defined(SECP256K1_GNUC_PREREQ)
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
# define SECP256K1_GNUC_PREREQ(_maj,_min) \
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
# else
# define SECP256K1_GNUC_PREREQ(_maj,_min) 0
# endif
# endif
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(2,7)
# define SECP256K1_INLINE __inline__
# elif (defined(_MSC_VER))
# define SECP256K1_INLINE __inline
# else
# define SECP256K1_INLINE
# endif
# else
# define SECP256K1_INLINE inline
# endif
/**Warning attributes
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
* some paranoid null checks. */
# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
# else
# define SECP256K1_WARN_UNUSED_RESULT
# endif
# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
# else
# define SECP256K1_ARG_NONNULL(_x)
# endif
/** Opaque data structure that holds context information (precomputed tables etc.).
* Only functions that take a pointer to a non-const context require exclusive
* access to it. Multiple functions that take a pointer to a const context may
* run simultaneously.
*/
typedef struct secp256k1_context_struct secp256k1_context_t;
/** Flags to pass to secp256k1_context_create. */
# define SECP256K1_CONTEXT_VERIFY (1 << 0)
# define SECP256K1_CONTEXT_SIGN (1 << 1)
/** Create a secp256k1 context object.
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
*/
secp256k1_context_t* secp256k1_context_create(
int flags
) SECP256K1_WARN_UNUSED_RESULT;
/** Copies a secp256k1 context object.
* Returns: a newly created context object.
* In: ctx: an existing context to copy
*/
secp256k1_context_t* secp256k1_context_clone(
const secp256k1_context_t* ctx
) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object.
* The context pointer may not be used afterwards.
*/
void secp256k1_context_destroy(
secp256k1_context_t* ctx
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an illegal argument is passed to
* an API call. The philosophy is that these shouldn't be dealt with through a
* specific return value, as calling code should not have branches to deal with
* the case that this code itself is broken.
* On the other hand, during debug stage, one would want to be informed about
* such mistakes, and the default (crashing) may be inadvisable.
* When this callback is triggered, the API function called is guaranteed not
* to cause a crash, though its return value and output arguments are
* undefined.
*/
void secp256k1_context_set_illegal_callback(
secp256k1_context_t* ctx,
void (*fun)(const char* message, void* data),
void* data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Set a callback function to be called when an internal consistency check
* fails. The default is crashing.
* This can only trigger in case of a hardware failure, miscompilation,
* memory corruption, serious bug in the library, or other error would can
* otherwise result in undefined behaviour. It will not trigger due to mere
* incorrect usage of the API (see secp256k1_context_set_illegal_callback
* for that). After this callback returns, anything may happen, including
* crashing.
*/
void secp256k1_context_set_error_callback(
secp256k1_context_t* ctx,
void (*fun)(const char* message, void* data),
void* data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Data type to hold a parsed and valid public key.
This data type should be considered opaque to the user, and only created
through API functions. It is not guaranteed to be compatible between
different implementations. If you need to convert to a format suitable
for storage or transmission, use secp256k1_ec_pubkey_serialize and
secp256k1_ec_pubkey_parse.
*/
typedef struct {
unsigned char data[64];
} secp256k1_pubkey_t;
/** Parse a variable-length public key into the pubkey object.
* Returns: 1 if the public key was fully valid.
* 0 if the public key could not be parsed or is invalid.
* In: ctx: a secp256k1 context object.
* input: pointer to a serialized public key
* inputlen: length of the array pointed to by input
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
* parsed version of input. If not, its value is undefined.
* This function supports parsing compressed (33 bytes, header byte 0x02 or
* 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
* byte 0x06 or 0x07) format public keys.
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
const secp256k1_context_t* ctx,
secp256k1_pubkey_t* pubkey,
const unsigned char *input,
int inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a pubkey object into a serialized byte sequence.
* Returns: 1 always.
* In: ctx: a secp256k1 context object.
* pubkey: a pointer to a secp256k1_pubkey_t containing an initialized
* public key.
* compressed: whether to serialize in compressed format.
* Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if
* compressed==1) byte array to place the serialized key in.
* outputlen: a pointer to an integer which will contain the serialized
* size.
*/
int secp256k1_ec_pubkey_serialize(
const secp256k1_context_t* ctx,
unsigned char *output,
int *outputlen,
const secp256k1_pubkey_t* pubkey,
int compressed
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Data type to hold a parsed ECDSA signature, optionally supporting pubkey
* recovery.
This data type should be considered opaque to the user, and only created
through API functions. It is not guaranteed to be compatible between
different implementations. If you need to convert to a format suitable
for storage or transmission, use secp256k1_ecdsa_signature_serialize_* and
secp256k1_ecdsa_signature_parse_* functions. */
typedef struct {
unsigned char data[65];
} secp256k1_ecdsa_signature_t;
/** Parse a DER ECDSA signature.
* Returns: 1 when the signature could be parsed, 0 otherwise.
* In: ctx: a secp256k1 context object
* input: a pointer to the signature to be parsed
* inputlen: the length of the array pointed to be input
* Out: sig: a pointer to a signature object
*
* Note that this function also supports some violations of DER.
*
* The resulting signature object will not support pubkey recovery.
*/
int secp256k1_ecdsa_signature_parse_der(
const secp256k1_context_t* ctx,
secp256k1_ecdsa_signature_t* sig,
const unsigned char *input,
int inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse a compact ECDSA signature (64 bytes + recovery id).
* Returns: 1 when the signature could be parsed, 0 otherwise
* In: ctx: a secp256k1 context object
* input64: a pointer to a 64-byte compact signature
* recid: the recovery id (0, 1, 2 or 3, or -1 for unknown)
* Out: sig: a pointer to a signature object
*
* If recid is not -1, the resulting signature object will support pubkey
* recovery.
*/
int secp256k1_ecdsa_signature_parse_compact(
const secp256k1_context_t* ctx,
secp256k1_ecdsa_signature_t* sig,
const unsigned char *input64,
int recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize an ECDSA signature in DER format.
* Returns: 1 if enough space was available to serialize, 0 otherwise
* In: ctx: a secp256k1 context object
* sig: a pointer to an initialized signature object
* Out: output: a pointer to an array to store the DER serialization
* In/Out: outputlen: a pointer to a length integer. Initially, this integer
* should be set to the length of output. After the call
* it will be set to the length of the serialization (even
* if 0 was returned).
*/
int secp256k1_ecdsa_signature_serialize_der(
const secp256k1_context_t* ctx,
unsigned char *output,
int *outputlen,
const secp256k1_ecdsa_signature_t* sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
* Returns: 1
* In: ctx: a secp256k1 context object
* sig: a pointer to an initialized signature object (cannot be NULL)
* Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)
* recid: a pointer to an integer to hold the recovery id (can be NULL).
*
* If recid is not NULL, the signature must support pubkey recovery.
*/
int secp256k1_ecdsa_signature_serialize_compact(
const secp256k1_context_t* ctx,
unsigned char *output64,
int *recid,
const secp256k1_ecdsa_signature_t* sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Verify an ECDSA signature.
* Returns: 1: correct signature
* 0: incorrect or unparseable signature
* In: ctx: a secp256k1 context object, initialized for verification.
* msg32: the 32-byte message hash being verified (cannot be NULL)
* sig: the signature being verified (cannot be NULL)
* pubkey: pointer to an initialized public key to verify with (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
const secp256k1_ecdsa_signature_t *sig,
const secp256k1_pubkey_t *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** A pointer to a function to deterministically generate a nonce.
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
* In: msg32: the 32-byte message hash being verified (will not be NULL)
* key32: pointer to a 32-byte secret key (will not be NULL)
* algo16: pointer to a 16-byte array describing the signature
* algorithm (will be NULL for ECDSA for compatibility).
* attempt: how many iterations we have tried to find a nonce.
* This will almost always be 0, but different attempt values
* are required to result in a different nonce.
* data: Arbitrary data pointer that is passed through.
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
* Except for test cases, this function should compute some cryptographic hash of
* the message, the key and the attempt.
*/
typedef int (*secp256k1_nonce_function_t)(
unsigned char *nonce32,
const unsigned char *msg32,
const unsigned char *key32,
const unsigned char *algo16,
unsigned int attempt,
const void *data
);
/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* extra entropy.
*/
extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
/** Create an ECDSA signature.
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
*
* The resulting signature will support pubkey recovery.
*
* The sig always has an s value in the lower half of the range (From 0x1
* to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
* inclusive), unlike many other implementations.
* With ECDSA a third-party can can forge a second distinct signature
* of the same message given a single initial signature without knowing
* the key by setting s to its additive inverse mod-order, 'flipping' the
* sign of the random point R which is not included in the signature.
* Since the forgery is of the same message this isn't universally
* problematic, but in systems where message malleability or uniqueness
* of signatures is important this can cause issues. This forgery can be
* blocked by all verifiers forcing signers to use a canonical form. The
* lower-S form reduces the size of signatures slightly on average when
* variable length encodings (such as DER) are used and is cheap to
* verify, making it a good choice. Security of always using lower-S is
* assured because anyone can trivially modify a signature after the
* fact to enforce this property. Adjusting it inside the signing
* function avoids the need to re-serialize or have curve specific
* constants outside of the library. By always using a canonical form
* even in applications where it isn't needed it becomes possible to
* impose a requirement later if a need is discovered.
* No other forms of ECDSA malleability are known and none seem likely,
* but there is no formal proof that ECDSA, even with this additional
* restriction, is free of other malleability. Commonly used serialization
* schemes will also accept various non-unique encodings, so care should
* be taken when this property is required for an application.
*/
int secp256k1_ecdsa_sign(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
secp256k1_ecdsa_signature_t *sig,
const unsigned char *seckey,
secp256k1_nonce_function_t noncefp,
const void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Recover an ECDSA public key from a signature.
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 0: otherwise.
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
* sig64: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
* Out: pubkey: pointer to the recoved public key (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
const secp256k1_ecdsa_signature_t *sig,
secp256k1_pubkey_t *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Verify an ECDSA secret key.
* Returns: 1: secret key is valid
* 0: secret key is invalid
* In: ctx: pointer to a context object (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
const secp256k1_context_t* ctx,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Compute the public key for a secret key.
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* seckey: pointer to a 32-byte private key (cannot be NULL)
* Out: pubkey: pointer to the created public key (cannot be NULL)
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const secp256k1_context_t* ctx,
secp256k1_pubkey_t *pubkey,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Export a private key in DER format.
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export(
const secp256k1_context_t* ctx,
const unsigned char *seckey,
unsigned char *privkey,
int *privkeylen,
int compressed
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Import a private key in DER format. */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import(
const secp256k1_context_t* ctx,
unsigned char *seckey,
const unsigned char *privkey,
int privkeylen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a private key by adding tweak to it. */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
const secp256k1_context_t* ctx,
unsigned char *seckey,
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a public key by adding tweak times the generator to it.
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
const secp256k1_context_t* ctx,
secp256k1_pubkey_t *pubkey,
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a private key by multiplying it with tweak. */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
const secp256k1_context_t* ctx,
unsigned char *seckey,
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a public key by multiplying it with tweak.
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const secp256k1_context_t* ctx,
secp256k1_pubkey_t *pubkey,
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization.
* Returns: 1: randomization successfully updated
* 0: error
* In: ctx: pointer to a context object (cannot be NULL)
* seed32: pointer to a 32-byte random seed (NULL resets to initial state)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context_t* ctx,
const unsigned char *seed32
) SECP256K1_ARG_NONNULL(1);
/** Add a number of public keys together.
* Returns: 1: the sum of the public keys is valid.
* 0: the sum of the public keys is not valid.
* In: ctx: pointer to a context object
* out: pointer to pubkey for placing the resulting public key
* (cannot be NULL)
* n: the number of public keys to add together (must be at least 1)
* ins: pointer to array of pointers to public keys (cannot be NULL)
* Use secp256k1_ec_pubkey_compress and secp256k1_ec_pubkey_decompress if the
* uncompressed format is needed.
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
const secp256k1_context_t* ctx,
secp256k1_pubkey_t *out,
int n,
const secp256k1_pubkey_t * const * ins
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
# ifdef __cplusplus
}
# endif
#endif

30
includes/secp256k1_ecdh.h

@ -0,0 +1,30 @@
#ifndef _SECP256K1_ECDH_
# define _SECP256K1_ECDH_
# include "secp256k1.h"
# ifdef __cplusplus
extern "C" {
# endif
/** Compute an EC Diffie-Hellman secret in constant time
* Returns: 1: exponentiation was successful
* 0: scalar was invalid (zero or overflow)
* In: ctx: pointer to a context object (cannot be NULL)
* point: pointer to a public point
* scalar: a 32-byte scalar with which to multiply the point
* Out: result: a 32-byte array which will be populated by an ECDH
* secret computed from the point and scalar
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
const secp256k1_context_t* ctx,
unsigned char *result,
const secp256k1_pubkey_t *point,
const unsigned char *scalar
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
# ifdef __cplusplus
}
# endif
#endif

186
includes/secp256k1_rangeproof.h

@ -0,0 +1,186 @@
#ifndef _SECP256K1_RANGEPROOF_
# define _SECP256K1_RANGEPROOF_
# include "secp256k1.h"
# ifdef __cplusplus
extern "C" {
# endif
#include <stdint.h>
/** Initialize a context for usage with Pedersen commitments. */
int secp256k1_pedersen_context_initialize(secp256k1_context_t* ctx);
/** Generate a pedersen commitment.
* Returns 1: commitment successfully created.
* 0: error
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
* value: unsigned 64-bit integer value to commit to.
* Out: commit: pointer to a 33-byte array for the commitment (cannot be NULL)
*
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
const secp256k1_context_t* ctx,
unsigned char *commit,
unsigned char *blind,
uint64_t value
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Computes the sum of multiple positive and negative blinding factors.
* Returns 1: sum successfully computed.
* 0: error
* In: ctx: pointer to a context object (cannot be NULL)
* blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
* n: number of factors pointed to by blinds.
* nneg: how many of the initial factors should be treated with a positive sign.
* Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
const secp256k1_context_t* ctx,
unsigned char *blind_out,
const unsigned char * const *blinds,
int n,
int npositive
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Verify a tally of pedersen commitments
* Returns 1: commitments successfully sum to zero.
* 0: Commitments do not sum to zero or other error.
* In: ctx: pointer to a context object, initialized for Pedersen commitment (cannot be NULL)
* commits: pointer to pointers to 33-byte character arrays for the commitments. (cannot be NULL if pcnt is non-zero)
* pcnt: number of commitments pointed to by commits.
* ncommits: pointer to pointers to 33-byte character arrays for negative commitments. (cannot be NULL if ncnt is non-zero)
* ncnt: number of commitments pointed to by ncommits.
* excess: signed 64bit amount to add to the total to bring it to zero, can be negative.
*
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) - excess*H == 0.
*
* A pedersen commitment is xG + vH where G and H are generators for the secp256k1 group and x is a blinding factor,
* while v is the committed value. For a collection of commitments to sum to zero both their blinding factors and
* values must sum to zero.
*
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
const secp256k1_context_t* ctx,
const unsigned char * const *commits,
int pcnt,
const unsigned char * const *ncommits,
int ncnt,
int64_t excess
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Initialize a context for usage with Pedersen commitments. */
int secp256k1_rangeproof_context_initialize(secp256k1_context_t* ctx);
/** Verify a proof that a committed value is within a range.
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs.
* 0: Proof failed or other error.
* In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL)
* commit: the 33-byte commitment being proved. (cannot be NULL)
* proof: pointer to character array with the proof. (cannot be NULL)
* plen: length of proof in bytes.
* Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
const secp256k1_context_t* ctx,
uint64_t *min_value,
uint64_t *max_value,
const unsigned char *commit,
const unsigned char *proof,
int plen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Verify a range proof proof and rewind the proof to recover information sent by its author.
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered.
* 0: Proof failed, rewind failed, or other error.
* In: ctx: pointer to a context object, initialized for range-proof and Pedersen commitment (cannot be NULL)
* commit: the 33-byte commitment being proved. (cannot be NULL)
* proof: pointer to character array with the proof. (cannot be NULL)
* plen: length of proof in bytes.
* nonce: 32-byte secret nonce used by the prover (cannot be NULL)
* In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment
* value_out: pointer to an unsigned int64 which has the exact value of the commitment.
* message_out: pointer to a 4096 byte character array to receive message data from the proof author.
* outlen: length of message data written to message_out.
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
const secp256k1_context_t* ctx,
unsigned char *blind_out,
uint64_t *value_out,
unsigned char *message_out,
int *outlen,
const unsigned char *nonce,
uint64_t *min_value,
uint64_t *max_value,
const unsigned char *commit,
const unsigned char *proof,
int plen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10);
/** Author a proof that a committed value is within a range.
* Returns 1: Proof successfully created.
* 0: Error
* In: ctx: pointer to a context object, initialized for range-proof, signing, and Pedersen commitment (cannot be NULL)
* proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL)
* min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount.
* commit: 33-byte array with the commitment being proved.
* blind: 32-byte blinding factor used by commit.
* nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.)
* exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18.
* (-1 is a special case that makes the value public. 0 is the most private.)
* min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64).
* value: Actual value of the commitment.
* In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof.
*
* If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64.
*
* If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.)
*
* This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding.
*
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
const secp256k1_context_t* ctx,
unsigned char *proof,
int *plen,
uint64_t min_value,
const unsigned char *commit,
const unsigned char *blind,
const unsigned char *nonce,
int exp,
int min_bits,
uint64_t value
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
/** Extract some basic information from a range-proof.
* Returns 1: Information successfully extracted.
* 0: Decode failed.
* In: ctx: pointer to a context object
* proof: pointer to character array with the proof.
* plen: length of proof in bytes.
* Out: exp: Exponent used in the proof (-1 means the value isn't private).
* mantissa: Number of bits covered by the proof.
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
const secp256k1_context_t* ctx,
int *exp,
int *mantissa,
uint64_t *min_value,
uint64_t *max_value,
const unsigned char *proof,
int plen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
# ifdef __cplusplus
}
# endif
#endif

173
includes/secp256k1_schnorr.h

@ -0,0 +1,173 @@
#ifndef _SECP256K1_SCHNORR_
# define _SECP256K1_SCHNORR_
# include "secp256k1.h"
# ifdef __cplusplus
extern "C" {
# endif
/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
* produces non-malleable 64-byte signatures which support public key recovery
* batch validation, and multiparty signing.
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was
* invalid.
* In: ctx: pointer to a context object, initialized for signing
* (cannot be NULL)
* msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL,
* secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation
* function (can be NULL)
* Out: sig64: pointer to a 64-byte array where the signature will be
* placed (cannot be NULL)
*/
int secp256k1_schnorr_sign(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
unsigned char *sig64,
const unsigned char *seckey,
secp256k1_nonce_function_t noncefp,
const void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Verify a signature created by secp256k1_schnorr_sign.
* Returns: 1: correct signature
* 0: incorrect signature
* In: ctx: a secp256k1 context object, initialized for verification.
* msg32: the 32-byte message hash being verified (cannot be NULL)
* sig64: the 64-byte signature being verified (cannot be NULL)
* pubkey: the public key to verify with (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
const unsigned char *sig64,
const secp256k1_pubkey_t *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Recover an EC public key from a Schnorr signature created using
* secp256k1_schnorr_sign.
* Returns: 1: public key successfully recovered (which guarantees a correct
* signature).
* 0: otherwise.
* In: ctx: pointer to a context object, initialized for
* verification (cannot be NULL)
* msg32: the 32-byte message hash assumed to be signed (cannot
* be NULL)
* sig64: signature as 64 byte array (cannot be NULL)
* Out: pubkey: pointer to a pubkey to set to the recovered public key
* (cannot be NULL).
*/
int secp256k1_schnorr_recover(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
const unsigned char *sig64,
secp256k1_pubkey_t *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Generate a nonce pair deterministically for use with
* secp256k1_schnorr_partial_sign.
* Returns: 1: valid nonce pair was generated.
* 0: otherwise (nonce generation function failed)
* In: ctx: pointer to a context object, initialized for signing
* (cannot be NULL)
* msg32: the 32-byte message hash assumed to be signed (cannot
* be NULL)
* sec32: the 32-byte private key (cannot be NULL)
* noncefp: pointer to a nonce generation function. If NULL,
* secp256k1_nonce_function_default is used
* noncedata: pointer to arbitrary data used by the nonce generation
* function (can be NULL)
* Out: pubnonce: public side of the nonce (cannot be NULL)
* privnonce32: private side of the nonce (32 byte) (cannot be NULL)
*
* Do not use the output as a private/public key pair for signing/validation.
*/
int secp256k1_schnorr_generate_nonce_pair(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
const unsigned char *sec32,
secp256k1_nonce_function_t noncefp,
const void* noncedata,
secp256k1_pubkey_t *pubnonce,
unsigned char *privnonce32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
/** Produce a partial Schnorr signature, which can be combined using
* secp256k1_schnorr_partial_combine, to end up with a full signature that is
* verifiable using secp256k1_schnorr_verify.
* Returns: 1: signature created succesfully.
* 0: no valid signature exists with this combination of keys, nonces
* and message (chance around 1 in 2^128)
* -1: invalid private key, nonce, or public nonces.
* In: ctx: pointer to context object, initialized for signing (cannot
* be NULL)
* msg32: pointer to 32-byte message to sign
* sec32: pointer to 32-byte private key
* secnonce32: pointer to 32-byte array containing our nonce
* pubnonce_others: pointer to pubkey containing the sum of the other's
* nonces (see secp256k1_ec_pubkey_combine)
* Out: sig64: pointer to 64-byte array to put partial signature in
*
* The intended procedure for creating a multiparty signature is:
* - Each signer S[i] with private key x[i] and public key Q[i] runs
* secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of
* private/public nonces.
* - All signers communicate their public nonces to each other (revealing your
* private nonce can lead to discovery of your private key, so it should be
* considered secret).
* - All signers combine all the public nonces they received (excluding their
* own) using secp256k1_ec_pubkey_combine to obtain an
* Rall[i] = sum(R[0..i-1,i+1..n]).
* - All signers produce a partial signature using
* secp256k1_schnorr_partial_sign, passing in their own private key x[i],
* their own private nonce k[i], and the sum of the others' public nonces
* Rall[i].
* - All signers communicate their partial signatures to each other.
* - Someone combines all partial signatures using
* secp256k1_schnorr_partial_combine, to obtain a full signature.
* - The resulting signature is validatable using secp256k1_schnorr_verify, with
* public key equal to the result of secp256k1_ec_pubkey_combine of the
* signers' public keys (sum(Q[0..n])).
*
* Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine
* function take their arguments in any order, and it is possible to
* pre-combine several inputs already with one call, and add more inputs later
* by calling the function again (they are commutative and associative).
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
unsigned char *sig64,
const unsigned char *sec32,
const unsigned char *secnonce32,
const secp256k1_pubkey_t *pubnonce_others
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
/** Combine multiple Schnorr partial signatures.
* Returns: 1: the passed signatures were succesfully combined.
* 0: the resulting signature is not valid (chance of 1 in 2^256)
* -1: some inputs were invalid, or the signatures were not created
* using the same set of nonces
* In: ctx: pointer to a context object
* sig64: pointer to a 64-byte array to place the combined signature
* (cannot be NULL)
* n: the number of signatures to combine (at least 1)
* Out: sig64sin: pointer to an array of n pointers to 64-byte input
* signatures
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
const secp256k1_context_t* ctx,
unsigned char *sig64,
int n,
const unsigned char * const * sig64sin
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
# ifdef __cplusplus
}
# endif
#endif
Loading…
Cancel
Save