This commit is contained in:
blackjok3r
2019-02-23 23:24:17 +08:00
parent aa6b693fee
commit 1b5d9b5032
3 changed files with 255 additions and 48 deletions

View File

@@ -89,7 +89,7 @@ the "msg" is what needs to be signed to create a valid spend
"numsigners": 2,
"commitment": "bbea1f2562eca01b9a1393c5dc188bdd44551aebf684f4459930f59dde01f7ae",
"result": "success"
}
}
on node with pubkey: 0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4
./komodo-cli -ac_name=MUSIG cclib session 18 '[1,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]'
@@ -221,7 +221,9 @@ struct musig_info
secp256k1_musig_partial_signature *partial_sig; //[N_SIGNERS];
int32_t myind,num;
uint8_t msg[32],pkhash[32],combpk[33];
} *MUSIG;
};
std::vector <struct musig_info *> MUSIG;
struct musig_info *musig_infocreate(int32_t myind,int32_t num)
{
@@ -431,14 +433,15 @@ UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
num = juint(jitem(params,1),0);
if ( myind < 0 || myind >= num || num <= 0 )
return(cclib_error(result,"illegal myindex and numsigners"));
if ( MUSIG != 0 )
musig_infofree(MUSIG), MUSIG = 0;
MUSIG = musig_infocreate(myind,num);
if ( musig_parsepubkey(ctx,MUSIG->combined_pk,jitem(params,2)) < 0 )
//if ( MUSIG[myind] != 0 )
// musig_infofree(MUSIG[myind]), MUSIG[myind] = 0;
struct musig_info *temp_musig = musig_infocreate(myind,num);
MUSIG.push_back(temp_musig);
if ( musig_parsepubkey(ctx,MUSIG[myind]->combined_pk,jitem(params,2)) < 0 )
return(cclib_error(result,"error parsing combined_pubkey"));
else if ( musig_parsehash(MUSIG->pkhash,jitem(params,3),32) < 0 )
else if ( musig_parsehash(MUSIG[myind]->pkhash,jitem(params,3),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( musig_parsehash(MUSIG->msg,jitem(params,4),32) < 0 )
else if ( musig_parsehash(MUSIG[myind]->msg,jitem(params,4),32) < 0 )
return(cclib_error(result,"error parsing msg"));
Myprivkey(privkey);
GetRandBytes(session,32);
@@ -468,13 +471,13 @@ UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
* my_index: index of this signer in the signers array
* seckey: the signer's 32-byte secret key (cannot be NULL)
*/
if ( secp256k1_musig_session_initialize(ctx,&MUSIG->session,MUSIG->signer_data, &MUSIG->nonce_commitments[MUSIG->myind * 32],session,MUSIG->msg,&MUSIG->combined_pk,MUSIG->pkhash,MUSIG->num,MUSIG->myind,privkey) > 0 )
if ( secp256k1_musig_session_initialize(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data, &MUSIG[myind]->nonce_commitments[MUSIG[myind]->myind * 32],session,MUSIG[myind]->msg,&MUSIG[myind]->combined_pk,MUSIG[myind]->pkhash,MUSIG[myind]->num,MUSIG[myind]->myind,privkey) > 0 )
{
memset(session,0,sizeof(session));
result.push_back(Pair("myind",(int64_t)myind));
result.push_back(Pair("numsigners",(int64_t)num));
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",MUSIG->nonce_commitments[MUSIG->myind*32 + i]);
sprintf(&str[i<<1],"%02x",MUSIG[myind]->nonce_commitments[MUSIG[myind]->myind*32 + i]);
str[64] = 0;
result.push_back(Pair("commitment",str));
result.push_back(Pair("result","success"));
@@ -492,18 +495,20 @@ UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
UniValue result(UniValue::VOBJ); int32_t i,n,ind; uint8_t pkhash[32]; CPubKey pk; char str[67];
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32]; CPubKey pk; char str[67];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 4 )
{
if ( musig_parsehash(pkhash,jitem(params,0),32) < 0 )
if ( (myind= juint(jitem(params,0),0)) < 0 )
return(cclib_error(result,"myind is wrong"));
if ( musig_parsehash(pkhash,jitem(params,1),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( memcmp(MUSIG->pkhash,pkhash,32) != 0 )
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
return(cclib_error(result,"pkhash doesnt match session pkhash"));
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG->num )
else if ( (ind= juint(jitem(params,2),0)) < 0 || ind >= MUSIG[myind]->num )
return(cclib_error(result,"illegal ind for session"));
else if ( musig_parsehash(&MUSIG->nonce_commitments[ind*32],jitem(params,2),32) < 0 )
else if ( musig_parsehash(&MUSIG[myind]->nonce_commitments[ind*32],jitem(params,3),32) < 0 )
return(cclib_error(result,"error parsing commitment"));
/** Gets the signer's public nonce given a list of all signers' data with commitments
*
@@ -521,14 +526,15 @@ UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
* number of signers participating in the MuSig.
*/
result.push_back(Pair("added_index",ind));
if ( secp256k1_musig_session_get_public_nonce(ctx,&MUSIG->session,MUSIG->signer_data,&MUSIG->nonces[MUSIG->myind],MUSIG->commitment_ptrs,MUSIG->num) > 0 )
fprintf(stderr, "COMMIT: number of MUSIG structs.%li using struct.%i addedindex.%i\n",MUSIG.size(),myind,ind);
if ( secp256k1_musig_session_get_public_nonce(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,&MUSIG[myind]->nonces[MUSIG[myind]->myind],MUSIG[myind]->commitment_ptrs,MUSIG[myind]->num) > 0 )
{
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG->nonces[MUSIG->myind],SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG[myind]->nonces[MUSIG[myind]->myind],SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
{
for (i=0; i<33; i++)
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
str[66] = 0;
result.push_back(Pair("myind",MUSIG->myind));
result.push_back(Pair("myind",MUSIG[myind]->myind));
result.push_back(Pair("nonce",str));
result.push_back(Pair("result","success"));
} else return(cclib_error(result,"error serializing nonce (pubkey)"));
@@ -539,26 +545,29 @@ UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
result.push_back(Pair("result","success"));
}
return(result);
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, commitment"));
} else return(cclib_error(result,"wrong number of params, need 4: myind, pkhash, ind, commitment"));
}
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
UniValue result(UniValue::VOBJ); int32_t i,n,ind; uint8_t pkhash[32],psig[32]; CPubKey pk; char str[67];
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32],psig[32]; CPubKey pk; char str[67];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 4 )
{
if ( musig_parsehash(pkhash,jitem(params,0),32) < 0 )
if ( (myind= juint(jitem(params,0),0)) < 0 )
return(cclib_error(result,"myind is wrong"));
if ( musig_parsehash(pkhash,jitem(params,1),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( memcmp(MUSIG->pkhash,pkhash,32) != 0 )
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
return(cclib_error(result,"pkhash doesnt match session pkhash"));
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG->num )
else if ( (ind= juint(jitem(params,2),0)) < 0 || ind >= MUSIG[myind]->num )
return(cclib_error(result,"illegal ind for session"));
else if ( musig_parsepubkey(ctx,MUSIG->nonces[ind],jitem(params,2)) < 0 )
else if ( musig_parsepubkey(ctx,MUSIG[myind]->nonces[ind],jitem(params,3)) < 0 )
return(cclib_error(result,"error parsing nonce"));
result.push_back(Pair("added_index",ind));
fprintf(stderr, "NONCE: number of MUSIG structs.%li using struct.%i addedindex.%i\n",MUSIG.size(),myind,ind);
/** Checks a signer's public nonce against a commitment to said nonce, and update
* data structure if they match
*
@@ -569,10 +578,16 @@ UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
* been used with `musig_session_get_public_nonce` or initialized
* with `musig_session_initialize_verifier`.
* In: nonce: signer's alleged public nonce (cannot be NULL)
*/
for (i=0; i<MUSIG->num; i++)
*
if ( ind != MUSIG[myind]->num-1 )
{
if ( secp256k1_musig_set_nonce(ctx,&MUSIG->signer_data[i],&MUSIG->nonces[i]) == 0 )
fprintf(stderr, "ind.%i MUSIG[myind]->num.%i\n", ind, MUSIG[myind]->num);
return(cclib_error(result,"need rest of nonce's to continue"));
}*/
for (i=0; i<MUSIG[myind]->num; i++)
{
fprintf(stderr, "setting nonce for index.%i\n",i);
if ( secp256k1_musig_set_nonce(ctx,&MUSIG[myind]->signer_data[i],&MUSIG[myind]->nonces[i]) == 0 )
return(cclib_error(result,"error setting nonce"));
}
/** Updates a session with the combined public nonce of all signers. The combined
@@ -593,45 +608,48 @@ UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
* adaptor: point to add to the combined public nonce. If NULL, nothing is
* added to the combined nonce.
*/
if ( secp256k1_musig_session_combine_nonces(ctx,&MUSIG->session,MUSIG->signer_data,MUSIG->num,NULL,NULL) > 0 )
if ( secp256k1_musig_session_combine_nonces(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,MUSIG[myind]->num,NULL,NULL) > 0 )
{
if ( secp256k1_musig_partial_sign(ctx,&MUSIG->session,&MUSIG->partial_sig[MUSIG->myind]) > 0 )
if ( secp256k1_musig_partial_sign(ctx,&MUSIG[myind]->session,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
{
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG->partial_sig[MUSIG->myind]) > 0 )
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
{
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",psig[i]);
str[64] = 0;
result.push_back(Pair("myind",MUSIG->myind));
result.push_back(Pair("myind",MUSIG[myind]->myind));
result.push_back(Pair("partialsig",str));
result.push_back(Pair("result","success"));
return(result);
} else return(cclib_error(result,"error serializing partial sig"));
} else return(cclib_error(result,"error making partial sig"));
} else return(cclib_error(result,"error combining nonces"));
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, nonce"));
} else return(cclib_error(result,"wrong number of params, need 4: myind, pkhash, ind, nonce"));
}
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
UniValue result(UniValue::VOBJ); int32_t i,ind,n; uint8_t pkhash[32],psig[32],out64[64]; char str[129]; secp256k1_schnorrsig sig;
UniValue result(UniValue::VOBJ); int32_t i,ind,myind,n; uint8_t pkhash[32],psig[32],out64[64]; char str[129]; secp256k1_schnorrsig sig;
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 4 )
{
if ( musig_parsehash(pkhash,jitem(params,0),32) < 0 )
if ( (myind= juint(jitem(params,0),0)) < 0 )
return(cclib_error(result,"myind is wrong"));
if ( musig_parsehash(pkhash,jitem(params,1),32) < 0 )
return(cclib_error(result,"error parsing pkhash"));
else if ( memcmp(MUSIG->pkhash,pkhash,32) != 0 )
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
return(cclib_error(result,"pkhash doesnt match session pkhash"));
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG->num )
else if ( (ind= juint(jitem(params,2),0)) < 0 || ind >= MUSIG[myind]->num )
return(cclib_error(result,"illegal ind for session"));
else if ( musig_parsehash(psig,jitem(params,2),32) < 0 )
else if ( musig_parsehash(psig,jitem(params,3),32) < 0 )
return(cclib_error(result,"error parsing psig"));
else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG->partial_sig[ind],psig) == 0 )
else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG[myind]->partial_sig[ind],psig) == 0 )
return(cclib_error(result,"error parsing partialsig"));
result.push_back(Pair("added_index",ind));
if ( secp256k1_musig_partial_sig_combine(ctx,&MUSIG->session,&sig,MUSIG->partial_sig,MUSIG->num) > 0 )
fprintf(stderr, "PARTIALSIG: number of MUSIG structs.%li using struct.%i addedindex.%i\n",MUSIG.size(),myind,ind);
if ( secp256k1_musig_partial_sig_combine(ctx,&MUSIG[myind]->session,&sig,MUSIG[myind]->partial_sig,MUSIG[myind]->num) > 0 )
{
if ( secp256k1_schnorrsig_serialize(ctx,out64,&sig) > 0 )
{
@@ -644,7 +662,7 @@ UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
}
else
{
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG->partial_sig[MUSIG->myind]) > 0 )
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
{
result.push_back(Pair("myind",ind));
for (i=0; i<32; i++)
@@ -656,7 +674,7 @@ UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
} else return(cclib_error(result,"error generating my partialsig"));
}
return(result);
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, partialsig"));
} else return(cclib_error(result,"wrong number of params, need 4: myind, pkhash, ind, partialsig"));
}
int testmain(void);

189
src/musigtest.py Executable file
View File

@@ -0,0 +1,189 @@
#!/usr/bin/env python3
import platform
import os
import re
import json
import random
import base58
import binascii
import hashlib
import sys
import time
from slickrpc import Proxy
# fucntion to define rpc_connection
def def_credentials(chain):
rpcport = '';
operating_system = platform.system()
if operating_system == 'Darwin':
ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo'
elif operating_system == 'Linux':
ac_dir = os.environ['HOME'] + '/.komodo'
elif operating_system == 'Windows':
ac_dir = '%s/komodo/' % os.environ['APPDATA']
if chain == 'KMD':
coin_config_file = str(ac_dir + '/komodo.conf')
else:
coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf')
with open(coin_config_file, 'r') as f:
for line in f:
l = line.rstrip()
if re.search('rpcuser', l):
rpcuser = l.replace('rpcuser=', '')
elif re.search('rpcpassword', l):
rpcpassword = l.replace('rpcpassword=', '')
elif re.search('rpcport', l):
rpcport = l.replace('rpcport=', '')
if len(rpcport) == 0:
if chain == 'KMD':
rpcport = 7771
else:
print("rpcport not in conf file, exiting")
print("check " + coin_config_file)
exit(1)
return (Proxy("http://%s:%s@127.0.0.1:%d" % (rpcuser, rpcpassword, int(rpcport))))
# generate address, validate address, dump private key
def genvaldump(rpc_connection):
# get new address
address = rpc_connection.getnewaddress()
# validate address
validateaddress_result = rpc_connection.validateaddress(address)
pubkey = validateaddress_result['pubkey']
address = validateaddress_result['address']
# dump private key for the address
privkey = rpc_connection.dumpprivkey(address)
# function output
output = [pubkey, privkey, address]
return(output)
CHAIN = 'MUSIG' #sys.argv[1]
rpc = def_credentials(CHAIN)
pubkeys = []
address_info = []
ret = input('Do you want to generate new pubkeys? ').lower()
if ret.startswith('y'):
numpks = int(input('Enter number of pubkeys to combine: '))
if os.path.isfile("list.json"):
print('Already have list.json, move it if you would like to generate a new set.')
sys.exit(0)
while len(address_info) < numpks:
addressinfo = genvaldump(rpc)
address_info.append(addressinfo)
f = open("list.json", "w+")
f.write(json.dumps(address_info))
else:
if os.path.isfile("list.json"):
with open('list.json') as list:
address_info = json.load(list)
else:
sys.exit('No list.json you need to create new pubkeys!')
for addressinfo in address_info:
pubkeys.append(addressinfo[0])
ret = rpc.setpubkey(pubkeys[0])
ret = rpc.cclib("combine", "18", str(pubkeys))
pkhash = str(ret['pkhash'])
combinedpk = str(ret['combined_pk'])
print('Your combined pubkey is: ' + combinedpk)
print('Your pkhash is: ' + pkhash)
amount = int(input('Enter amount to send: '))
tmp = str([combinedpk, amount])
hex = rpc.cclib("send", "18", tmp)['hex']
senttxid = rpc.sendrawtransaction(hex)
print('Your senttxid is: ' + senttxid)
print("Waiting for tx to be confirmed")
while True:
confirmed = int(rpc.gettransaction(senttxid)["confirmations"])
if not confirmed:
time.sleep(10)
else:
print('SentTX confirmed')
break
scriptPubKey = rpc.getrawtransaction(senttxid,1)['vout'][1]['scriptPubKey']['hex']
print('Your scriptPubKey is: ' + scriptPubKey)
tmp = str([senttxid, scriptPubKey])
msg = rpc.cclib("calcmsg", "18", tmp)['msg']
print('Your msg is: ' + msg)
i = 0;
commitments = []
for pubkey in pubkeys:
ret = rpc.setpubkey(pubkey)
tmp = str([i, len(pubkeys), combinedpk, pkhash, msg])
commitments.append(rpc.cclib("session", "18", tmp)['commitment'])
i = i + 1
print(commitments)
i = 0
nonces = []
for pubkey in pubkeys:
ret = rpc.setpubkey(pubkey)
n = 0
for commitment in commitments:
if n == i:
n = n + 1
continue;
tmp = str([i, pkhash, n, commitment])
ret = rpc.cclib("commit", "18", tmp)
if len(ret) == 4:
nonces.append(ret['nonce'])
n = n + 1
i = i + 1
print(nonces)
i = 0
partialsigs = []
for pubkey in pubkeys:
ret = rpc.setpubkey(pubkey)
n = 0
for nonce in nonces:
#if n == i:
# n = n + 1
# continue;
tmp = str([i, pkhash, n, nonce])
ret = rpc.cclib("nonce", "18", tmp)
print(ret)
if len(ret) == 4:
partialsigs.append(ret['partialsig'])
n = n + 1
i = i + 1
print(partialsigs)
i = 0
combinedsigs = []
for pubkey in pubkeys:
ret = rpc.setpubkey(pubkey)
n = 0
for partialsig in partialsigs:
if n == i:
n = n + 1
continue;
tmp = str([i, pkhash, n, partialsig])
ret = rpc.cclib("partialsig", "18", tmp)
if len(ret) == 4:
combinedsigs.append(ret['combinedsig'])
n = n + 1
i = i + 1
print(combinedsigs)
tmp = str([msg, combinedpk, combinedsigs[0]])
ret = rpc.cclib("verify", "18", tmp)
print(ret)
tmp = str([sendtxid, scriptPubKey, combinedsigs[0]])
ret = rpc.cclib("spend", "18", tmp)
print(ret)

View File

@@ -5308,8 +5308,8 @@ UniValue setpubkey(const UniValue& params, bool fHelp)
char Raddress[64];
uint8_t pubkey33[33];
if ( NOTARY_PUBKEY33[0] == 0 )
{
//if ( NOTARY_PUBKEY33[0] == 0 )
//{
if (strlen(params[0].get_str().c_str()) == 66)
{
decode_hex(pubkey33,33,(char *)params[0].get_str().c_str());
@@ -5337,14 +5337,14 @@ UniValue setpubkey(const UniValue& params, bool fHelp)
USE_EXTERNAL_PUBKEY = 1;
}
} else result.push_back(Pair("error", "pubkey is wrong length, must be 66 char hex string."));
}
/*}
else
{
result.push_back(Pair("error", "Can only set pubkey once, to change it you need to restart your daemon, pubkey in use is below."));
pubkey2addr((char *)Raddress,(uint8_t *)NOTARY_PUBKEY33);
std::string address_ret; address_ret.assign(Raddress);
result.push_back(Pair("address",address_ret));
}
}*/
result.push_back(Pair("pubkey", NOTARY_PUBKEY));
return result;
}