diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3ace05cb9..a9fb7a01b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,9 +32,9 @@ build:ubuntu: variables: DOCKER_DRIVER: overlay2 cache: - key: "${CI_JOB_NAME}${CI_COMMIT_REF_NAME}" + key: ${CI_COMMIT_REF_SLUG} paths: - - depends/built + - depends/ script: - zcutil/build.sh -j$(nproc) - mkdir ${PACKAGE_DIR_LINUX} diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index bfd57e61d..c770917ea 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -72,12 +72,11 @@ CClib_methods[] = { (char *)"sudoku", (char *)"pending", (char *)"", 0, 0, 'U', EVAL_SUDOKU }, { (char *)"sudoku", (char *)"solution", (char *)"txid solution timestamps[81]", 83, 83, 'S', EVAL_SUDOKU }, { (char *)"musig", (char *)"calcmsg", (char *)"sendtxid scriptPubKey", 2, 2, 'C', EVAL_MUSIG }, - { (char *)"musig", (char *)"combine", (char *)"pubkeys ...", 2, 256, 'P', EVAL_MUSIG }, - { (char *)"musig", (char *)"session", (char *)"msg pkhash", 2, 2, 'R', EVAL_MUSIG }, - { (char *)"musig", (char *)"commit", (char *)"pubkeys ...", 2, 256, 'H', EVAL_MUSIG }, - { (char *)"musig", (char *)"nonce", (char *)"pubkeys ...", 2, 256, 'N', EVAL_MUSIG }, - { (char *)"musig", (char *)"partialsign", (char *)"pubkeys ...", 2, 256, 'S', EVAL_MUSIG }, - { (char *)"musig", (char *)"sigcombine", (char *)"pubkeys ...", 2, 256, 'M', EVAL_MUSIG }, + { (char *)"musig", (char *)"combine", (char *)"pubkeys ...", 2, 999999999, 'P', EVAL_MUSIG }, + { (char *)"musig", (char *)"session", (char *)"myindex,numsigners,combined_pk,pkhash,msg32", 5, 5, 'R', EVAL_MUSIG }, + { (char *)"musig", (char *)"commit", (char *)"pkhash,ind,commitment", 3, 3, 'H', EVAL_MUSIG }, + { (char *)"musig", (char *)"nonce", (char *)"pkhash,ind,nonce", 3, 3, 'N', EVAL_MUSIG }, + { (char *)"musig", (char *)"partialsig", (char *)"pkhash,ind,partialsig", 3, 3, 'S', EVAL_MUSIG }, { (char *)"musig", (char *)"verify", (char *)"msg sig pubkey", 3, 3, 'V', EVAL_MUSIG }, { (char *)"musig", (char *)"send", (char *)"combined_pk amount", 2, 2, 'x', EVAL_MUSIG }, { (char *)"musig", (char *)"spend", (char *)"sendtxid sig destpubkey", 3, 3, 'y', EVAL_MUSIG }, @@ -116,8 +115,7 @@ UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); -UniValue musig_partialsign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); -UniValue musig_sigcombine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); @@ -229,10 +227,8 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr) return(musig_commit(txfee,cp,params)); else if ( strcmp(method,"nonce") == 0 ) // returns combined nonce if ready return(musig_nonce(txfee,cp,params)); - else if ( strcmp(method,"partialsign") == 0 ) - return(musig_partialsign(txfee,cp,params)); - else if ( strcmp(method,"sigcombine") == 0 ) - return(musig_sigcombine(txfee,cp,params)); + else if ( strcmp(method,"partialsig") == 0 ) + return(musig_partialsig(txfee,cp,params)); else if ( strcmp(method,"verify") == 0 ) return(musig_verify(txfee,cp,params)); else if ( strcmp(method,"send") == 0 ) @@ -584,37 +580,7 @@ uint256 juint256(cJSON *obj) #else #include "sudoku.cpp" - -/* -#include "../secp256k1/src/util.h" -#include "../secp256k1/src/num_impl.h" -#include "../secp256k1/src/field_impl.h" -#include "../secp256k1/src/scalar_impl.h" -#include "../secp256k1/src/group_impl.h" -#include "../secp256k1/src/scratch_impl.h" -#include "../secp256k1/src/ecmult_impl.h" -#include "../secp256k1/src/ecmult_const_impl.h" -#include "../secp256k1/src/ecmult_gen_impl.h" -#include "../secp256k1/src/ecdsa_impl.h" -#include "../secp256k1/src/eckey_impl.h" -#include "../secp256k1/src/hash_impl.h" - - - -typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data); -extern "C" void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge); -extern "C" int secp256k1_nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter); -extern "C" int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey); -extern "C" void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx); - -#define ARG_CHECK(cond) do { \ -if (EXPECT(!(cond), 0)) { \ -secp256k1_callback_call(&ctx->illegal_callback, #cond); \ -return 0; \ -} \ -} while(0)*/ - -//#include "../secp256k1/src/secp256k1.c" #include "musig.cpp" +#include "../secp256k1/src/modules/musig/example.c" #endif diff --git a/src/cc/faucet.cpp b/src/cc/faucet.cpp index b44337461..b794d9b1c 100644 --- a/src/cc/faucet.cpp +++ b/src/cc/faucet.cpp @@ -124,9 +124,9 @@ bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //int height = it->first.blockHeight; if ( CCduration(numblocks,it->first.txhash) > 0 && numblocks > 3 ) { - //fprintf(stderr,"would return error %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks); return eval->Invalid("faucet is only for brand new addresses"); } + //fprintf(stderr,"txid %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks); } retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) diff --git a/src/cc/makerogue b/src/cc/makerogue index ff175c586..51caef6e2 100755 --- a/src/cc/makerogue +++ b/src/cc/makerogue @@ -3,10 +3,14 @@ cd rogue; if [ "$HOST" = "x86_64-w64-mingw32" ]; then echo building rogue.exe... + ./configure --host=x86_64-w64-mingw32 mkdir ncurses && cd ncurses + echo $PWD wget https://invisible-island.net/datafiles/release/mingw32.zip - unzip mingw32.zip && delete mingw32.zip + unzip mingw32.zip && rm mingw32.zip + echo lib archive cleaned cd .. + echo $PWD if make -f Makefile_win "$@"; then echo rogue.exe build SUCCESSFUL cd .. diff --git a/src/cc/musig.cpp b/src/cc/musig.cpp index ec7f5e788..446f9333d 100644 --- a/src/cc/musig.cpp +++ b/src/cc/musig.cpp @@ -20,13 +20,14 @@ "combined_pk": "032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b", "result": "success" } + the combined_pk and pkhash will be needed for various other rpc calls */ /* second, send 0.777 coins to the combined_pk ./c cclib send 18 \"[%22032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b%22,0.777]\" { - "hex": "0400008085202f8901bf7afcbbab7a5e1ba20c8010325e199305afa7d15b4bc86a589a512201d39924000000004847304402203e0cff8aaa831dd990afd979bbc0a648316f77407cb5e02780d18e0670f5172a0220283d5c52d0406b10c508cc2b19dd6dbe2420e7c5cf431a1d41072d0eec28edb901ffffffff03b0c2a10400000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cca91e223700000000232102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac0000000000000000266a24127821032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b00000000900000000000000000000000000000", - "txid": "cb5309ed249da95e2b5696eb763a8736e2fff1d14922ada737b931494ca3d2be", + "hex": "0400008085202f8908018bbc4a0acf0f896680b84cc1000ec5530042fa3cf7471ab5c11cde56f6d0e60000000048473044022041a900fa57e54f939b797d09f0cee81ab9a79d978cd473ef3fc9f09c7678ad6b02206386bd15ee7ee8224a984fdd1d2a094738d082aec06028a5846d7bc61ddf16ca01ffffffff0b969f0e1ea787f0cc4e81d128353bd1cb670ab89bd1db4b47fbb7e872cd39fb00000000494830450221008c5de4b196e57b0dd94aa415950adf274e3e6859b82cf218729af84c1f15e76c022024aeab7eda63e6a652ef488bf26a8dc4ef8d2d4aa5746726085bfe5f169a5db701ffffffff0b36b70b43457fab377f28fb22da5a3e9d8186a37daae18cf0f710a221ab26250000000048473044022004ec20ae7490e7adabf9a3f78e4a58df84a3245485bfdd40f421cafe61d19c340220456d2b6f3c6e88632027c02606a0af1c21208d05f2de0826fbf4dfe7391ec83901ffffffff0aaff3cfe4ca22b97b6179a6f7cfac91945e5440e9438b89d1ec09500167176a0000000048473044022074dcad30c8ab9ed79a3ac69169611fc9e5f4b76a561b183461d968249316997f022063b25decaa285f494d277b9c8c2bcf6445b7929a304542e89c0645828d30a1a901ffffffff090e1bb92e9bf404a0d6455701b21af3dbf6765e61a1dc28b7c0f608ec4f12da000000004847304402202f9182c532c66138a6bdfcbb85a06cf1bf1532f2bf8f63170ef20843e4a81d0202207612a4353eb9606e84621c444ec7db1b683ff29c56127bda2d5e9c0eb13dbbc001ffffffff08a57005c7a40a923b1a510820b07f7318d760fe2a233b077d918cce357ad3af00000000484730440220643d60c68634fb2e0f6656389fc70c9f84c7086fc6e35b0fa26297e844f6c5fc02201d79669e073efe738d47de0130fdcba875e284e18fd478c0e6834d46632d8b8101ffffffff068cfd0ea6c0f5d401c67ec38f92425a9e59b0d5ade55bb2971ea955675a17bd00000000484730440220747139724248da4bcc1e5e3828e0ea811756e1fad0ebc40aeb006fd8079d46e402200d8f1c229c79494b5617e4373a3e083966dcd74571323f9d334be901d53871fa01ffffffff0200382fb6984b6128bb75115346242809c6555274e0cacef822825a2b4d231700000000484730440220454fcac398f6913fb4d8ed330f110f9cf62eec6c8cdb67d5df1effd2cf8222d5022017f6323630669777573e342e870c88727a917cc06c33611ebbd9d1fccc1dcd3701ffffffff03b0c2a10400000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cc40ca220000000000232102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac0000000000000000266a24127821032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b00000000460100000000000000000000000000", + "txid": "2c4159bb19212dcaa412ae37de7d72398f063194053e04a65b0facf767ebcc68", "result": "success" } @@ -45,17 +46,104 @@ } change script: 2102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac - sendtxid: cb5309ed249da95e2b5696eb763a8736e2fff1d14922ada737b931494ca3d2be + sendtxid: 2c4159bb19212dcaa412ae37de7d72398f063194053e04a65b0facf767ebcc68 broadcast sendtxid and wait for it to be confirmed. then get the msg we need to sign: - ./c cclib calcmsg 18 \"[%22cb5309ed249da95e2b5696eb763a8736e2fff1d14922ada737b931494ca3d2be%22,%222102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac%22]\" + ./c cclib calcmsg 18 \"[%222c4159bb19212dcaa412ae37de7d72398f063194053e04a65b0facf767ebcc68%22,%222102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac%22]\" { "result": "success", - "msg": "63b799913d4c9487f321b32d6ae8614f653f38e0b50d4df4bc1d36339ea18485" + "msg": "caa64ba398ddfe5c33d8c70a61e556caa0e69b19d93110c5a458a1b37ad44cb0" + } + +the "msg" is what needs to be signed to create a valid spend + + now on each signing node, a session needs to be created: + 5 args: ind, numsigners, combined_pk, pkhash, message to be signed + + on node with pubkey: 02aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848 + ./c cclib session 18 \"[0,2,%22032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b%22,%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,%22caa64ba398ddfe5c33d8c70a61e556caa0e69b19d93110c5a458a1b37ad44cb0%22]\" + { + "myind": 0, + "numsigners": 2, + "commitment": "e82228c10d0e100477630349150dea744d3b2790dcd347511a1a98199840cda4", + "result": "success" + } + + on node with pubkey: 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 + ./c cclib session 18 \"[1,2,%22032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b%22,%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,%22caa64ba398ddfe5c33d8c70a61e556caa0e69b19d93110c5a458a1b37ad44cb0%22]\" + { + "myind": 1, + "numsigners": 2, + "commitment": "6e426e850ddc45e7742cfb6321781c00ee69a995ab12fa1f9ded7fe43658babf", + "result": "success" + } + + now we need to get the commitment from each node to the other one. the session already put the commitment for each node into the global struct. Keep in mind there is a single global struct with session unique to each cclib session call. that means no restarting any deamon in the middle of the process on any of the nodes and only call cclib session a single time. this is an artificial restriction just to simplify the initial implementation of musig + + ./c cclib commit 18 \"[%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,1,%226e426e850ddc45e7742cfb6321781c00ee69a995ab12fa1f9ded7fe43658babf%22]\" + { + "added_index": 1, + "myind": 0, + "nonce": "0261671b0a6de416938cf035c98f8af37c6ca88bbbd1bcce693d709d4919b010e1", + "result": "success" + } + + ./c cclib commit 18 \"[%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,0,%22e82228c10d0e100477630349150dea744d3b2790dcd347511a1a98199840cda4%22]\" + { + "added_index": 0, + "myind": 1, + "nonce": "02570f62a625ceb19a754a053152b162810c3e403df63f3d443e85bdacc74bfdfe", + "result": "success" + } + + Now exchange the revealed nonces to each node: + + ./c cclib nonce 18 \"[%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,1,%2202570f62a625ceb19a754a053152b162810c3e403df63f3d443e85bdacc74bfdfe%22]\" + + { + "added_index": 1, + "myind": 0, + "partialsig": "3f21885e6d2d020e1473435ccd148a61cdcb1d1105867fed45913185dc0acf59", + "result": "success" + } + + ./c cclib nonce 18 \"[%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,0,%220261671b0a6de416938cf035c98f8af37c6ca88bbbd1bcce693d709d4919b010e1%22]\" + { + "added_index": 0, + "myind": 0, + "myind": 1, + "partialsig": "af7f28455fb2e988d81068cd9d800879cd334036a8300118dc307b777a38c1ed", + "result": "success" + } + + Almost there! final step is to exchange the partial sigs between signers + ./c cclib partialsig 18 \"[%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,1,%22af7f28455fb2e988d81068cd9d800879cd334036a8300118dc307b777a38c1ed%22]\" + { + "added_index": 1, + "result": "success", + "combinedsig": "5e64dc5dda93b2d3f25fe44b2aaca69b8f15d21f70e2bc1c2c53e17262d941bbeea0b0a3ccdfeb96ec83ac2a6a9492db9afe5d47adb6810621c1acfd56439146" } + + ./c cclib partialsig 18 \"[%225be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba%22,0,%223f21885e6d2d020e1473435ccd148a61cdcb1d1105867fed45913185dc0acf59%22]\" + + { + "added_index": 0, + "result": "success", + "combinedsig": "5e64dc5dda93b2d3f25fe44b2aaca69b8f15d21f70e2bc1c2c53e17262d941bbeea0b0a3ccdfeb96ec83ac2a6a9492db9afe5d47adb6810621c1acfd56439146" + } + Notice both nodes generated the same combined signature! + + Now for a sanity test, we can use the verify call to make sure this sig will work with the msg needed for the spend: + + ./c cclib verify 18 \"[%22caa64ba398ddfe5c33d8c70a61e556caa0e69b19d93110c5a458a1b37ad44cb0%22,%22032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b%22,%225e64dc5dda93b2d3f25fe44b2aaca69b8f15d21f70e2bc1c2c53e17262d941bbeea0b0a3ccdfeb96ec83ac2a6a9492db9afe5d47adb6810621c1acfd56439146%22]\" + + + and finally the spend: sendtxid, scriptPubKey, musig + +./c cclib spend 18 \"[%222c4159bb19212dcaa412ae37de7d72398f063194053e04a65b0facf767ebcc68%22,%222102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac%22,%225e64dc5dda93b2d3f25fe44b2aaca69b8f15d21f70e2bc1c2c53e17262d941bbeea0b0a3ccdfeb96ec83ac2a6a9492db9afe5d47adb6810621c1acfd56439146%22]\" */ @@ -74,20 +162,79 @@ struct secp256k1_context_struct { secp256k1_callback error_callback; }; -extern "C" int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); -extern "C" int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk); -extern "C" int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64); -extern "C" int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys); - //#include "../secp256k1/include/secp256k1.h" //#include "../secp256k1/include/secp256k1_schnorrsig.h" #include "../secp256k1/include/secp256k1_musig.h" +extern "C" int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); +extern "C" int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk); +extern "C" int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64); +extern "C" int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys); +extern "C" int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey); +extern "C" int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig); + #define MUSIG_PREVN 0 // for now, just use vout0 for the musig output #define MUSIG_TXFEE 10000 +struct musig_info +{ + secp256k1_musig_session session; + secp256k1_pubkey combined_pk; + uint8_t *nonce_commitments,**commitment_ptrs; // 32*N_SIGNERS + secp256k1_musig_session_signer_data *signer_data; //[N_SIGNERS]; + secp256k1_pubkey *nonces; //[N_SIGNERS]; + secp256k1_musig_partial_signature *partial_sig; //[N_SIGNERS]; + int32_t myind,num; + uint8_t msg[32],pkhash[32],combpk[33]; +} *MUSIG; + +struct musig_info *musig_infocreate(int32_t myind,int32_t num) +{ + int32_t i; struct musig_info *mp = (struct musig_info *)calloc(1,sizeof(*mp)); + mp->myind = myind, mp->num = num; + mp->nonce_commitments = (uint8_t *)calloc(num,32); + mp->commitment_ptrs = (uint8_t **)calloc(num,sizeof(*mp->commitment_ptrs)); + for (i=0; icommitment_ptrs[i] = &mp->nonce_commitments[i*32]; + mp->signer_data = (secp256k1_musig_session_signer_data *)calloc(num,sizeof(*mp->signer_data)); + mp->nonces = (secp256k1_pubkey *)calloc(num,sizeof(*mp->nonces)); + mp->partial_sig = (secp256k1_musig_partial_signature *)calloc(num,sizeof(*mp->partial_sig)); + return(mp); +} + +void musig_infofree(struct musig_info *mp) +{ + if ( mp->partial_sig != 0 ) + { + GetRandBytes((uint8_t *)mp->partial_sig,mp->num*sizeof(*mp->partial_sig)); + free(mp->partial_sig); + } + if ( mp->nonces != 0 ) + { + GetRandBytes((uint8_t *)mp->nonces,mp->num*sizeof(*mp->nonces)); + free(mp->nonces); + } + if ( mp->signer_data != 0 ) + { + GetRandBytes((uint8_t *)mp->signer_data,mp->num*sizeof(*mp->signer_data)); + free(mp->signer_data); + } + if ( mp->nonce_commitments != 0 ) + { + GetRandBytes((uint8_t *)mp->nonce_commitments,mp->num*32); + free(mp->nonce_commitments); + } + if ( mp->commitment_ptrs != 0 ) + { + GetRandBytes((uint8_t *)mp->commitment_ptrs,mp->num*sizeof(*mp->commitment_ptrs)); + free(mp->commitment_ptrs); + } + GetRandBytes((uint8_t *)mp,sizeof(*mp)); + free(mp); +} + CScript musig_sendopret(uint8_t funcid,CPubKey pk) { CScript opret; uint8_t evalcode = EVAL_MUSIG; @@ -173,6 +320,27 @@ UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) } else return(cclib_error(result,"couldnt parse params")); } +int32_t musig_parsepubkey(secp256k1_context *ctx,secp256k1_pubkey &spk,cJSON *item) +{ + char *hexstr; + if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == 66 ) + { + CPubKey pk(ParseHex(hexstr)); + if ( secp256k1_ec_pubkey_parse(ctx,&spk,pk.begin(),33) > 0 ) + return(1); + } else return(-1); +} + +int32_t musig_parsehash(uint8_t *hash32,cJSON *item,int32_t len) +{ + char *hexstr; + if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == len*2 ) + { + decode_hex(hash32,len,hexstr); + return(0); + } else return(-1); +} + UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { static secp256k1_context *ctx; @@ -185,13 +353,9 @@ UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) //fprintf(stderr,"n.%d args.(%s)\n",n,jprint(params,0)); for (i=0; i 0 ) - pubkeys.push_back(spk); - else return(cclib_error(result,"error parsing pk")); - } else return(cclib_error(result,"all pubkeys must be 33 bytes hexdata")); + if ( musig_parsepubkey(ctx,spk,jitem(params,i)) < 0 ) + return(cclib_error(result,"error parsing pk")); + pubkeys.push_back(spk); } if ( secp256k1_musig_pubkey_combine(ctx,NULL,&combined_pk,pkhash,&pubkeys[0],n) > 0 ) { @@ -215,191 +379,278 @@ UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - /** Initializes a signing session for a signer - * - * Returns: 1: session is successfully initialized - * 0: session could not be initialized: secret key or secret nonce overflow - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) - * Out: session: the session structure to initialize (cannot be NULL) - * signers: an array of signers' data to be initialized. Array length must - * equal to `n_signers` (cannot be NULL) - * nonce_commitment32: filled with a 32-byte commitment to the generated nonce - * (cannot be NULL) - * In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be - * NULL). If a non-unique session_id32 was given then a partial - * signature will LEAK THE SECRET KEY. - * msg32: the 32-byte message to be signed. Shouldn't be NULL unless you - * require sharing public nonces before the message is known - * because it reduces nonce misuse resistance. If NULL, must be - * set with `musig_session_set_msg` before signing and verifying. - * combined_pk: the combined public key of all signers (cannot be NULL) - * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be - * NULL) - * n_signers: length of signers array. Number of signers participating in - * the MuSig. Must be greater than 0 and at most 2^32 - 1. - * 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[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, N_SIGNERS, i, seckeys[i])) - //return 0; - // randombytes_buf(buf, num); - - //nonce_commitment_ptr[i] = &nonce_commitment[i][0]; - return(result); + static secp256k1_context *ctx; + UniValue result(UniValue::VOBJ); int32_t i,n,myind,num; char *pkstr,*pkhashstr,*msgstr; uint8_t session[32],msg[32],pkhash[32],privkey[32],pub33[33]; 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)) == 5 ) + { + myind = juint(jitem(params,0),0); + 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 ) + return(cclib_error(result,"error parsing combined_pubkey")); + else if ( musig_parsehash(MUSIG->pkhash,jitem(params,3),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + else if ( musig_parsehash(MUSIG->msg,jitem(params,4),32) < 0 ) + return(cclib_error(result,"error parsing msg")); + Myprivkey(privkey); + GetRandBytes(session,32); + /** Initializes a signing session for a signer + * + * Returns: 1: session is successfully initialized + * 0: session could not be initialized: secret key or secret nonce overflow + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: session: the session structure to initialize (cannot be NULL) + * signers: an array of signers' data to be initialized. Array length must + * equal to `n_signers` (cannot be NULL) + * nonce_commitment32: filled with a 32-byte commitment to the generated nonce + * (cannot be NULL) + * In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be + * NULL). If a non-unique session_id32 was given then a partial + * signature will LEAK THE SECRET KEY. + * msg32: the 32-byte message to be signed. Shouldn't be NULL unless you + * require sharing public nonces before the message is known + * because it reduces nonce misuse resistance. If NULL, must be + * set with `musig_session_set_msg` before signing and verifying. + * combined_pk: the combined public key of all signers (cannot be NULL) + * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be + * NULL) + * n_signers: length of signers array. Number of signers participating in + * the MuSig. Must be greater than 0 and at most 2^32 - 1. + * 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 ) + { + 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]); + str[64] = 0; + result.push_back(Pair("commitment",str)); + result.push_back(Pair("result","success")); + return(result); + } + else + { + memset(session,0,sizeof(session)); + return(cclib_error(result,"couldnt initialize session")); + } + } else return(cclib_error(result,"wrong number of params, need 5: myindex, numsigners, combined_pk, pkhash, msg32")); } UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - /** Gets the signer's public nonce given a list of all signers' data with commitments - * - * Returns: 1: public nonce is written in nonce - * 0: signer data is missing commitments or session isn't initialized - * for signing - * Args: ctx: pointer to a context object (cannot be NULL) - * session: the signing session to get the nonce from (cannot be NULL) - * signers: an array of signers' data initialized with - * `musig_session_initialize`. Array length must equal to - * `n_commitments` (cannot be NULL) - * Out: nonce: the nonce (cannot be NULL) - * In: commitments: array of 32-byte nonce commitments (cannot be NULL) - * n_commitments: the length of commitments and signers array. Must be the total - * number of signers participating in the MuSig. - */ - // Set nonce commitments in the signer data and get the own public nonce - //if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS)) - // return 0; - - return(result); + 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]; + if ( ctx == 0 ) + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 ) + { + if ( musig_parsehash(pkhash,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + else if ( memcmp(MUSIG->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 ) + return(cclib_error(result,"illegal ind for session")); + else if ( musig_parsehash(&MUSIG->nonce_commitments[ind*32],jitem(params,2),32) < 0 ) + return(cclib_error(result,"error parsing commitment")); + /** Gets the signer's public nonce given a list of all signers' data with commitments + * + * Returns: 1: public nonce is written in nonce + * 0: signer data is missing commitments or session isn't initialized + * for signing + * Args: ctx: pointer to a context object (cannot be NULL) + * session: the signing session to get the nonce from (cannot be NULL) + * signers: an array of signers' data initialized with + * `musig_session_initialize`. Array length must equal to + * `n_commitments` (cannot be NULL) + * Out: nonce: the nonce (cannot be NULL) + * In: commitments: array of 32-byte nonce commitments (cannot be NULL) + * n_commitments: the length of commitments and signers array. Must be the total + * 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 ) + { + if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG->nonces[MUSIG->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("nonce",str)); + result.push_back(Pair("result","success")); + } else return(cclib_error(result,"error serializing nonce (pubkey)")); + } + else + { + result.push_back(Pair("status","not enough commitments")); + result.push_back(Pair("result","success")); + } + return(result); + } else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, commitment")); } UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - /** Checks a signer's public nonce against a commitment to said nonce, and update - * data structure if they match - * - * Returns: 1: commitment was valid, data structure updated - * 0: commitment was invalid, nothing happened - * Args: ctx: pointer to a context object (cannot be NULL) - * signer: pointer to the signer data to update (cannot be NULL). Must have - * 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) - */ - //if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], &nonce[j])) { - - - /** Updates a session with the combined public nonce of all signers. The combined - * public nonce is the sum of every signer's public nonce. - * - * Returns: 1: nonces are successfully combined - * 0: a signer's nonce is missing - * Args: ctx: pointer to a context object (cannot be NULL) - * session: session to update with the combined public nonce (cannot be - * NULL) - * signers: an array of signers' data, which must have had public nonces - * set with `musig_set_nonce`. Array length must equal to `n_signers` - * (cannot be NULL) - * n_signers: the length of the signers array. Must be the total number of - * signers participating in the MuSig. - * Out: nonce_is_negated: a pointer to an integer that indicates if the combined - * public nonce had to be negated. - * adaptor: point to add to the combined public nonce. If NULL, nothing is - * added to the combined nonce. - */ - // after all nonces: if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) { + static secp256k1_context *ctx; + UniValue result(UniValue::VOBJ); int32_t i,n,ind; 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 ( musig_parsehash(pkhash,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + else if ( memcmp(MUSIG->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 ) + return(cclib_error(result,"illegal ind for session")); + else if ( musig_parsepubkey(ctx,MUSIG->nonces[ind],jitem(params,2)) < 0 ) + return(cclib_error(result,"error parsing nonce")); + result.push_back(Pair("added_index",ind)); + /** Checks a signer's public nonce against a commitment to said nonce, and update + * data structure if they match + * + * Returns: 1: commitment was valid, data structure updated + * 0: commitment was invalid, nothing happened + * Args: ctx: pointer to a context object (cannot be NULL) + * signer: pointer to the signer data to update (cannot be NULL). Must have + * 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; inum; i++) + { + if ( secp256k1_musig_set_nonce(ctx,&MUSIG->signer_data[i],&MUSIG->nonces[i]) == 0 ) + return(cclib_error(result,"error setting nonce")); + } + /** Updates a session with the combined public nonce of all signers. The combined + * public nonce is the sum of every signer's public nonce. + * + * Returns: 1: nonces are successfully combined + * 0: a signer's nonce is missing + * Args: ctx: pointer to a context object (cannot be NULL) + * session: session to update with the combined public nonce (cannot be + * NULL) + * signers: an array of signers' data, which must have had public nonces + * set with `musig_set_nonce`. Array length must equal to `n_signers` + * (cannot be NULL) + * n_signers: the length of the signers array. Must be the total number of + * signers participating in the MuSig. + * Out: nonce_is_negated: a pointer to an integer that indicates if the combined + * public nonce had to be negated. + * 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_partial_sign(ctx,&MUSIG->session,&MUSIG->partial_sig[MUSIG->myind]) > 0 ) + { + if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG->partial_sig[MUSIG->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("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")); +} + +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; + if ( ctx == 0 ) + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 ) + { + if ( musig_parsehash(pkhash,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + else if ( memcmp(MUSIG->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 ) + return(cclib_error(result,"illegal ind for session")); + else if ( musig_parsehash(psig,jitem(params,2),32) < 0 ) + return(cclib_error(result,"error parsing psig")); + else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG->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 ) + { + if ( secp256k1_schnorrsig_serialize(ctx,out64,&sig) > 0 ) + { + result.push_back(Pair("result","success")); + for (i=0; i<64; i++) + sprintf(&str[i<<1],"%02x",out64[i]); + str[128] = 0; + result.push_back(Pair("combinedsig",str)); + } else return(cclib_error(result,"error serializing combinedsig")); + } + else + { + if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG->partial_sig[MUSIG->myind]) > 0 ) + { + result.push_back(Pair("myind",ind)); + for (i=0; i<32; i++) + sprintf(&str[i<<1],"%02x",psig[i]); + str[64] = 0; + result.push_back(Pair("partialsig",str)); + result.push_back(Pair("result","success")); + result.push_back(Pair("status","need more partialsigs")); + } 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")); } -UniValue musig_partialsign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - /** Produces a partial signature - * - * Returns: 1: partial signature constructed - * 0: session in incorrect or inconsistent state - * Args: ctx: pointer to a context object (cannot be NULL) - * session: active signing session for which the combined nonce has been - * computed (cannot be NULL) - * Out: partial_sig: partial signature (cannot be NULL) - */ - //if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) { - /** Parse and verify a MuSig partial signature. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: pointer to a signature object - * In: in32: pointer to the 32-byte signature to be parsed - * - * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature verification with it is - * guaranteed to fail for every message and public key. - */ - //SECP256K1_API int secp256k1_musig_partial_signature_parse( - - return(result); -} - -UniValue musig_sigcombine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - /** Checks that an individual partial signature verifies - * - * This function is essential when using protocols with adaptor signatures. - * However, it is not essential for regular MuSig's, in the sense that if any - * partial signatures does not verify, the full signature will also not verify, so the - * problem will be caught. But this function allows determining the specific party - * who produced an invalid signature, so that signing can be restarted without them. - * - * Returns: 1: partial signature verifies - * 0: invalid signature or bad data - * Args: ctx: pointer to a context object (cannot be NULL) - * session: active session for which the combined nonce has been computed - * (cannot be NULL) - * signer: data for the signer who produced this signature (cannot be NULL) - * In: partial_sig: signature to verify (cannot be NULL) - * pubkey: public key of the signer who produced the signature (cannot be NULL) - */ - //if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) { - return 0; - /** Combines partial signatures - * - * Returns: 1: all partial signatures have values in range. Does NOT mean the - * resulting signature verifies. - * 0: some partial signature had s/r out of range - * Args: ctx: pointer to a context object (cannot be NULL) - * session: initialized session for which the combined nonce has been - * computed (cannot be NULL) - * Out: sig: complete signature (cannot be NULL) - * In: partial_sigs: array of partial signatures to combine (cannot be NULL) - * n_sigs: number of signatures in the partial_sigs array - */ - // after all partials: return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS return(result); -} - +int testmain(void); UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - /** Verify a Schnorr signature. - * - * Returns: 1: correct signature - * 0: incorrect or unparseable signature - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig: the signature being verified (cannot be NULL) - * msg32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: pointer to a public key to verify with (cannot be NULL) - */ - // if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) { - return(result); + static secp256k1_context *ctx; + UniValue result(UniValue::VOBJ); int32_t i,n; uint8_t msg[32],musig64[64]; secp256k1_pubkey combined_pk; secp256k1_schnorrsig musig; char str[129]; + testmain(); + if ( ctx == 0 ) + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 ) + { + if ( musig_parsehash(msg,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + else if ( musig_parsepubkey(ctx,combined_pk,jitem(params,1)) < 0 ) + return(cclib_error(result,"error parsing combined_pk")); + else if ( musig_parsehash(musig64,jitem(params,2),64) < 0 ) + return(cclib_error(result,"error parsing musig64")); + for (i=0; i<32; i++) + sprintf(&str[i*2],"%02x",msg[i]); + str[64] = 0; + result.push_back(Pair("msg",str)); + result.push_back(Pair("combined_pk",jstr(jitem(params,1),0))); + for (i=0; i<64; i++) + sprintf(&str[i*2],"%02x",musig64[i]); + str[128] = 0; + result.push_back(Pair("combinedsig",str)); + if ( secp256k1_schnorrsig_parse(ctx,&musig,&musig64[0]) > 0 ) + { + if ( secp256k1_schnorrsig_verify(ctx,&musig,msg,&combined_pk) > 0 ) + { + result.push_back(Pair("result","success")); + return(result); + } else return(cclib_error(result,"musig didnt verify")); + } else return(cclib_error(result,"couldnt parse musig64")); + } else return(cclib_error(result,"wrong number of params, need 3: msg, combined_pk, combinedsig")); } // helpers for rpc calls that generate/validate onchain tx @@ -449,7 +700,7 @@ UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { static secp256k1_context *ctx; CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,pk; secp256k1_pubkey combined_pk; char *scriptstr,*musigstr; uint8_t msg[32]; CTransaction vintx; uint256 prevhash,hashBlock; int32_t n,numvouts; CTxOut vout; secp256k1_schnorrsig musig; + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,pk; secp256k1_pubkey combined_pk; char *scriptstr,*musigstr; uint8_t msg[32]; CTransaction vintx; uint256 prevhash,hashBlock; int32_t i,n,numvouts; char str[129]; CTxOut vout; secp256k1_schnorrsig musig; if ( ctx == 0 ) ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) @@ -459,13 +710,15 @@ UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) prevhash = juint256(jitem(params,0)); scriptstr = jstr(jitem(params,1),0); musigstr = jstr(jitem(params,2),0); - if ( is_hexstr(scriptstr,0) != 0 && is_hexstr(musigstr,0) != 128 ) + if ( is_hexstr(scriptstr,0) != 0 && is_hexstr(musigstr,0) == 128 ) { if ( txfee == 0 ) txfee = MUSIG_TXFEE; mypk = pubkey2pk(Mypubkey()); std::vector musig64(ParseHex(musigstr)); - CScript scriptPubKey(ParseHex(scriptstr)); + CScript scriptPubKey; + scriptPubKey.resize(strlen(scriptstr)/2); + decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr); if ( myGetTransaction(prevhash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 ) { vout.nValue = vintx.vout[0].nValue - txfee; @@ -476,8 +729,24 @@ UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 ) { musig_prevoutmsg(msg,prevhash,vout.scriptPubKey); + { + for (i=0; i<32; i++) + sprintf(&str[i*2],"%02x",msg[i]); + str[64] = 0; + result.push_back(Pair("msg",str)); + for (i=0; i<33; i++) + sprintf(&str[i*2],"%02x",((uint8_t *)pk.begin())[i]); + str[66] = 0; + result.push_back(Pair("combined_pk",str)); + for (i=0; i<64; i++) + sprintf(&str[i*2],"%02x",musig64[i]); + str[128] = 0; + result.push_back(Pair("combinedsig",str)); + } if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) ) + { return(cclib_error(result,"musig didnt validate")); + } mtx.vin.push_back(CTxIn(prevhash,MUSIG_PREVN)); mtx.vout.push_back(vout); rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_spendopret('y',pk,musig64)); @@ -486,7 +755,7 @@ UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) } else return(cclib_error(result,"couldnt decode send opret")); } else return(cclib_error(result,"couldnt find vin0")); } else return(cclib_error(result,"script or musig is not hex")); - } else return(cclib_error(result,"need to have exactly 3 params prevhash, scriptPubKey, musig")); + } else return(cclib_error(result,"need to have exactly 3 params sendtxid, scriptPubKey, musig")); } else return(cclib_error(result,"params parse error")); } diff --git a/src/cc/rogue/Makefile_win b/src/cc/rogue/Makefile_win index dbc900e48..6e558960c 100644 --- a/src/cc/rogue/Makefile_win +++ b/src/cc/rogue/Makefile_win @@ -26,10 +26,10 @@ O=o CC = x86_64-w64-mingw32-gcc #CFLAGS=-O2 -CFLAGS= -g -O2 -I./ncurses/include +CFLAGS= -g -O2 -I./ncurses/include -I./ncurses/include/ncursesw -I../../../depends/x86_64-w64-mingw32/include #LIBS=-lcurses -LIBS = -L./ncurses/lib -lncursesw +LIBS = -L./ncurses/lib -lncursesw -lcurl #RM=rm -f RM = rm -f diff --git a/src/cc/rogue/main.c b/src/cc/rogue/main.c index 93391d153..3461445ee 100644 --- a/src/cc/rogue/main.c +++ b/src/cc/rogue/main.c @@ -41,7 +41,11 @@ typedef union _bits256 bits256; double OS_milliseconds() { struct timeval tv; double millis; + #ifdef __MINGW32__ + mingw_gettimeofday(&tv,NULL); + #else gettimeofday(&tv,NULL); + #endif millis = ((double)tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.); //printf("tv_sec.%ld usec.%d %f\n",tv.tv_sec,tv.tv_usec,millis); return(millis); diff --git a/src/cc/rogue/mdport.c b/src/cc/rogue/mdport.c index 988e1c7b7..fd53be72c 100644 --- a/src/cc/rogue/mdport.c +++ b/src/cc/rogue/mdport.c @@ -705,7 +705,9 @@ md_erasechar() #elif defined(VERASE) return(_tty.c_cc[VERASE]); /* process erase character */ #else + #ifndef __MINGW32__ return(_tty.sg_erase); /* process erase character */ + #endif #endif } @@ -717,7 +719,9 @@ md_killchar() #elif defined(VKILL) return(_tty.c_cc[VKILL]); #else + #ifndef __MINGW32__ return(_tty.sg_kill); + #endif #endif } diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 57ce1e14b..213e382a1 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -833,7 +833,7 @@ UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } else return(cclib_error(result,"couldnt reparse params")); } -char *rogue_extractgame(char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *rogueaddr) +char *rogue_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *rogueaddr) { CPubKey roguepk; int32_t i,num,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct rogue_player P,endP; roguepk = GetUnspendable(cp,0); @@ -854,19 +854,22 @@ char *rogue_extractgame(char *str,int32_t *numkeysp,std::vector &newdat } if ( keystrokes != 0 ) { - sprintf(fname,"rogue.%llu.0",(long long)seed); - if ( (fp= fopen(fname,"wb")) != 0 ) + if ( makefiles != 0 ) { - if ( fwrite(keystrokes,1,numkeys,fp) != numkeys ) - fprintf(stderr,"error writing %s\n",fname); - fclose(fp); - } - sprintf(fname,"rogue.%llu.player",(long long)seed); - if ( (fp= fopen(fname,"wb")) != 0 ) - { - if ( fwrite(&playerdata[0],1,(int32_t)playerdata.size(),fp) != playerdata.size() ) - fprintf(stderr,"error writing %s\n",fname); - fclose(fp); + sprintf(fname,"rogue.%llu.0",(long long)seed); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( fwrite(keystrokes,1,numkeys,fp) != numkeys ) + fprintf(stderr,"error writing %s\n",fname); + fclose(fp); + } + sprintf(fname,"rogue.%llu.player",(long long)seed); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( fwrite(&playerdata[0],1,(int32_t)playerdata.size(),fp) != playerdata.size() ) + fprintf(stderr,"error writing %s\n",fname); + fclose(fp); + } } num = rogue_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); @@ -914,7 +917,7 @@ UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) GetCCaddress1of2(cp,rogueaddr,roguepk,pk); result.push_back(Pair("rogueaddr",rogueaddr)); str[0] = 0; - if ( (keystrokes= rogue_extractgame(str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) + if ( (keystrokes= rogue_extractgame(1,str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) { result.push_back(Pair("status","success")); flag = 1; @@ -1240,7 +1243,7 @@ int32_t rogue_playerdata_validate(uint256 &playertxid,struct CCcontract_info *cp roguepk = GetUnspendable(cp,0); GetCCaddress1of2(cp,rogueaddr,roguepk,pk); //fprintf(stderr,"call extractgame\n"); - if ( (keystrokes= rogue_extractgame(str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) + if ( (keystrokes= rogue_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) { free(keystrokes); //fprintf(stderr,"extracted.(%s)\n",str); diff --git a/src/secp256k1/include/secp256k1_musig.h b/src/secp256k1/include/secp256k1_musig.h index 7e974e36d..84106822a 100644 --- a/src/secp256k1/include/secp256k1_musig.h +++ b/src/secp256k1/include/secp256k1_musig.h @@ -132,7 +132,12 @@ typedef struct { * key (cannot be NULL) * n_pubkeys: length of pubkeys array */ -SECP256K1_API int secp256k1_musig_pubkey_combine( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_pubkey_combine( const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, @@ -167,7 +172,12 @@ SECP256K1_API int secp256k1_musig_pubkey_combine( * my_index: index of this signer in the signers array * seckey: the signer's 32-byte secret key (cannot be NULL) */ -SECP256K1_API int secp256k1_musig_session_initialize( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_session_initialize( const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, @@ -196,7 +206,12 @@ SECP256K1_API int secp256k1_musig_session_initialize( * n_commitments: the length of commitments and signers array. Must be the total * number of signers participating in the MuSig. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce( const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, @@ -225,7 +240,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi * participating in the MuSig. Must be greater than 0 and at most * 2^32 - 1. */ -SECP256K1_API int secp256k1_musig_session_initialize_verifier( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_session_initialize_verifier( const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, @@ -247,7 +267,12 @@ SECP256K1_API int secp256k1_musig_session_initialize_verifier( * with `musig_session_initialize_verifier`. * In: nonce: signer's alleged public nonce (cannot be NULL) */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const secp256k1_pubkey *nonce @@ -271,7 +296,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( * adaptor: point to add to the combined public nonce. If NULL, nothing is * added to the combined nonce. */ -SECP256K1_API int secp256k1_musig_session_combine_nonces( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_session_combine_nonces( const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, @@ -288,7 +318,12 @@ SECP256K1_API int secp256k1_musig_session_combine_nonces( * session: the session structure to update with the message (cannot be NULL) * In: msg32: the 32-byte message to be signed (cannot be NULL) */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_set_msg( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_set_msg( const secp256k1_context* ctx, secp256k1_musig_session *session, const unsigned char *msg32 @@ -301,7 +336,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_set_msg( * Out: out32: pointer to a 32-byte array to store the serialized signature * In: sig: pointer to the signature */ -SECP256K1_API int secp256k1_musig_partial_signature_serialize( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_partial_signature_serialize( const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig @@ -318,7 +358,12 @@ SECP256K1_API int secp256k1_musig_partial_signature_serialize( * encoded numbers are out of range, signature verification with it is * guaranteed to fail for every message and public key. */ -SECP256K1_API int secp256k1_musig_partial_signature_parse( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_partial_signature_parse( const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32 @@ -333,7 +378,12 @@ SECP256K1_API int secp256k1_musig_partial_signature_parse( * computed (cannot be NULL) * Out: partial_sig: partial signature (cannot be NULL) */ -SECP256K1_API int secp256k1_musig_partial_sign( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_partial_sign( const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig @@ -356,7 +406,12 @@ SECP256K1_API int secp256k1_musig_partial_sign( * In: partial_sig: signature to verify (cannot be NULL) * pubkey: public key of the signer who produced the signature (cannot be NULL) */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, @@ -376,7 +431,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif * In: partial_sigs: array of partial signatures to combine (cannot be NULL) * n_sigs: number of signatures in the partial_sigs array */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine( const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, @@ -396,7 +456,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combi * be NULL) * nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` */ -SECP256K1_API int secp256k1_musig_partial_sig_adapt( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + int secp256k1_musig_partial_sig_adapt( const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, @@ -419,7 +484,12 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt( * n_partial_sigs: number of elements in partial_sigs array * nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif + SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor( const secp256k1_context* ctx, unsigned char *sec_adaptor32, const secp256k1_schnorrsig *sig, diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h index 9dea16653..e4d02f34f 100644 --- a/src/secp256k1/include/secp256k1_schnorrsig.h +++ b/src/secp256k1/include/secp256k1_schnorrsig.h @@ -28,7 +28,12 @@ typedef struct { * * See secp256k1_schnorrsig_parse for details about the encoding. */ -SECP256K1_API int secp256k1_schnorrsig_serialize( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif +int secp256k1_schnorrsig_serialize( const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig @@ -50,7 +55,12 @@ SECP256K1_API int secp256k1_schnorrsig_serialize( * encoded numbers are out of range, signature validation with it is * guaranteed to fail for every message and public key. */ -SECP256K1_API int secp256k1_schnorrsig_parse( +#ifdef __cplusplus +extern "C" +#else +SECP256K1_API +#endif +int secp256k1_schnorrsig_parse( const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64 diff --git a/src/secp256k1/src/modules/musig/example.c b/src/secp256k1/src/modules/musig/example.c index ceae18686..70d183e7d 100644 --- a/src/secp256k1/src/modules/musig/example.c +++ b/src/secp256k1/src/modules/musig/example.c @@ -9,11 +9,11 @@ * Additionally, see the documentation in include/secp256k1_musig.h. */ -#include +/*#include #include #include #include -#include +#include */ /* Number of public keys involved in creating the aggregate signature */ #define N_SIGNERS 3 @@ -122,43 +122,43 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS); } - int main(void) { + int testmain(void) { secp256k1_context* ctx; int i; unsigned char seckeys[N_SIGNERS][32]; secp256k1_pubkey pubkeys[N_SIGNERS]; secp256k1_pubkey combined_pk; - unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; + unsigned char msg[32] = "this_could_be_the_hash_of_a_msg"; secp256k1_schnorrsig sig; /* Create a context for signing and verification */ ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - printf("Creating key pairs......"); + fprintf(stderr,"Creating key pairs......"); for (i = 0; i < N_SIGNERS; i++) { if (!create_key(ctx, seckeys[i], &pubkeys[i])) { - printf("FAILED\n"); + fprintf(stderr,"FAILED\n"); return 1; } } - printf("ok\n"); - printf("Combining public keys..."); + fprintf(stderr,"ok\n"); + fprintf(stderr,"Combining public keys..."); if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) { - printf("FAILED\n"); + fprintf(stderr,"FAILED\n"); return 1; } - printf("ok\n"); - printf("Signing message........."); + fprintf(stderr,"ok\n"); + fprintf(stderr,"Signing message........."); if (!sign(ctx, seckeys, pubkeys, msg, &sig)) { - printf("FAILED\n"); + fprintf(stderr,"FAILED\n"); return 1; } - printf("ok\n"); - printf("Verifying signature....."); + fprintf(stderr,"ok\n"); + fprintf(stderr,"Verifying signature....."); if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) { - printf("FAILED\n"); + fprintf(stderr,"FAILED\n"); return 1; } - printf("ok\n"); + fprintf(stderr,"ok\n"); secp256k1_context_destroy(ctx); return 0; }