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/configure.ac b/configure.ac index 9a1a75f53..12256c0cc 100644 --- a/configure.ac +++ b/configure.ac @@ -884,6 +884,7 @@ fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) +AM_CONDITIONAL([TARGET_LINUX], [test x$TARGET_OS = xlinux]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes]) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 7a0439ba7..3c180b0ce 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_69_0 -$(package)_download_path=https://dl.bintray.com/boostorg/release/1.69.0/source +$(package)_version=1_66_0 +$(package)_download_path=https://dl.bintray.com/boostorg/release/1.66.0/source $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406 +$(package)_sha256_hash=5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9 define $(package)_set_vars $(package)_config_opts_release=variant=release diff --git a/src/Makefile.am b/src/Makefile.am index fa2c17b5d..f06de8910 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,7 +36,8 @@ LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl endif if TARGET_DARWIN LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl -else +endif +if TARGET_LINUX LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl endif @@ -578,7 +579,8 @@ komodod_LDADD += libcc.dylib $(LIBSECP256K1) endif if TARGET_WINDOWS komodod_LDADD += libcc.dll $(LIBSECP256K1) -else +endif +if TARGET_LINUX komodod_LDADD += libcc.so $(LIBSECP256K1) endif diff --git a/src/assetchains.json b/src/assetchains.json index 1b23bc616..91baf9829 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -224,5 +224,21 @@ "addnode": [ "37.187.225.231" ] - } + }, + { + "ac_name": "OUR", + "ac_reward": "1478310502", + "ac_halving": "525600", + "ac_cc": "42", + "ac_supply": "100000000", + "ac_perc": "77700", + "ac_staked": "93", + "ac_pubkey": "02652a3f3e00b3a1875a918314f0bac838d6dd189a346fa623f5efe9541ac0b98c", + "ac_public": "1", + "addnode": [ + "51.255.195.65", + "217.182.129.38", + "95.216.150.177" + ] +} ] diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index bfd57e61d..f7749d99f 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -37,6 +37,7 @@ std::string MYCCLIBNAME = (char *)"rogue"; #define EVAL_SUDOKU 17 #define EVAL_MUSIG 18 +#define EVAL_DILITHIUM 19 std::string MYCCLIBNAME = (char *)"sudoku"; #endif @@ -72,15 +73,20 @@ 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 }, + { (char *)"musig", (char *)"spend", (char *)"sendtxid sig scriptPubKey", 3, 3, 'y', EVAL_MUSIG }, + { (char *)"dilithium", (char *)"keypair", (char *)"[hexseed]", 0, 1, 'K', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"register", (char *)"handle, [hexseed]", 1, 2, 'R', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"sign", (char *)"msg [hexseed]", 1, 2, 'S', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"verify", (char *)"pubtxid msg sig", 3, 3, 'V', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"send", (char *)"handle pubtxid amount", 3, 3, 'x', EVAL_DILITHIUM }, + { (char *)"dilithium", (char *)"spend", (char *)"sendtxid scriptPubKey [hexseed]", 2, 3, 'y', EVAL_DILITHIUM }, #endif }; @@ -116,11 +122,19 @@ 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); + +bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); +UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_keypair(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_sign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue dilithium_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); + #endif cJSON *cclib_reparse(int32_t *nump,char *jsonstr) // assumes origparams will be freed by caller @@ -229,10 +243,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 ) @@ -247,6 +259,28 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr) return(result); } } + else if ( cp->evalcode == EVAL_DILITHIUM ) + { + if ( strcmp(method,"send") == 0 ) + return(dilithium_send(txfee,cp,params)); + else if ( strcmp(method,"spend") == 0 ) + return(dilithium_spend(txfee,cp,params)); + else if ( strcmp(method,"keypair") == 0 ) + return(dilithium_keypair(txfee,cp,params)); + else if ( strcmp(method,"register") == 0 ) + return(dilithium_register(txfee,cp,params)); + else if ( strcmp(method,"sign") == 0 ) + return(dilithium_sign(txfee,cp,params)); + else if ( strcmp(method,"verify") == 0 ) + return(dilithium_verify(txfee,cp,params)); + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid dilithium method")); + result.push_back(Pair("method",method)); + return(result); + } + } #endif else { @@ -373,6 +407,8 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C return(sudoku_validate(cp,height,eval,tx)); else if ( cp->evalcode == EVAL_MUSIG ) return(musig_validate(cp,height,eval,tx)); + else if ( cp->evalcode == EVAL_DILITHIUM ) + return(dilithium_validate(cp,height,eval,tx)); else return eval->Invalid("invalid evalcode"); #endif } @@ -544,6 +580,15 @@ uint256 juint256(cJSON *obj) return(revuint256(tmp)); } +int32_t cclib_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); +} #ifdef BUILD_ROGUE #include "rogue_rpc.cpp" @@ -584,37 +629,8 @@ 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 "dilithium.c" +//#include "../secp256k1/src/modules/musig/example.c" #endif diff --git a/src/cc/dapps/cJSON.c b/src/cc/dapps/cJSON.c old mode 100755 new mode 100644 diff --git a/src/cc/dilithium.c b/src/cc/dilithium.c new file mode 100644 index 000000000..9a9c4de71 --- /dev/null +++ b/src/cc/dilithium.c @@ -0,0 +1,3269 @@ +/* Based on the public domain implementation in + * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html + * by Ronny Van Keer + * and the public domain "TweetFips202" implementation + * from https://twitter.com/tweetfips202 + * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */ + +#include + +#define DBENCH_START() +#define DBENCH_STOP(arg) + +#include "dilithium.h" + + +#define NROUNDS 24 +#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) + +/************************************************* +* Name: load64 +* +* Description: Load 8 bytes into uint64_t in little-endian order +* +* Arguments: - const uint8_t *x: pointer to input byte array +* +* Returns the loaded 64-bit unsigned integer +**************************************************/ +static uint64_t load64(const uint8_t *x) { + uint32_t i; + uint64_t r = 0; + + for (i = 0; i < 8; ++i) + r |= (uint64_t)x[i] << 8*i; + + return r; +} + +/************************************************* +* Name: store64 +* +* Description: Store a 64-bit integer to array of 8 bytes in little-endian order +* +* Arguments: - uint8_t *x: pointer to the output byte array (allocated) +* - uint64_t u: input 64-bit unsigned integer +**************************************************/ +static void store64(uint8_t *x, uint64_t u) { + uint32_t i; + + for(i = 0; i < 8; ++i) + x[i] = u >> 8*i; +} + +/* Keccak round constants */ +static const uint64_t KeccakF_RoundConstants[NROUNDS] = { + (uint64_t)0x0000000000000001ULL, + (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, + (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, + (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, + (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, + (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, + (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, + (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, + (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, + (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, + (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, + (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008008ULL +}; + +/************************************************* +* Name: KeccakF1600_StatePermute +* +* Description: The Keccak F1600 Permutation +* +* Arguments: - uint64_t *state: pointer to input/output Keccak state +**************************************************/ +static void KeccakF1600_StatePermute(uint64_t *state) +{ + int round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + //copyFromState(A, state) + Aba = state[ 0]; + Abe = state[ 1]; + Abi = state[ 2]; + Abo = state[ 3]; + Abu = state[ 4]; + Aga = state[ 5]; + Age = state[ 6]; + Agi = state[ 7]; + Ago = state[ 8]; + Agu = state[ 9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for( round = 0; round < NROUNDS; round += 2 ) + { + // prepareTheta + BCa = Aba^Aga^Aka^Ama^Asa; + BCe = Abe^Age^Ake^Ame^Ase; + BCi = Abi^Agi^Aki^Ami^Asi; + BCo = Abo^Ago^Ako^Amo^Aso; + BCu = Abu^Agu^Aku^Amu^Asu; + + //thetaRhoPiChiIotaPrepareTheta(round , A, E) + Da = BCu^ROL(BCe, 1); + De = BCa^ROL(BCi, 1); + Di = BCe^ROL(BCo, 1); + Do = BCi^ROL(BCu, 1); + Du = BCo^ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = ROL(Age, 44); + Aki ^= Di; + BCi = ROL(Aki, 43); + Amo ^= Do; + BCo = ROL(Amo, 21); + Asu ^= Du; + BCu = ROL(Asu, 14); + Eba = BCa ^((~BCe)& BCi ); + Eba ^= (uint64_t)KeccakF_RoundConstants[round]; + Ebe = BCe ^((~BCi)& BCo ); + Ebi = BCi ^((~BCo)& BCu ); + Ebo = BCo ^((~BCu)& BCa ); + Ebu = BCu ^((~BCa)& BCe ); + + Abo ^= Do; + BCa = ROL(Abo, 28); + Agu ^= Du; + BCe = ROL(Agu, 20); + Aka ^= Da; + BCi = ROL(Aka, 3); + Ame ^= De; + BCo = ROL(Ame, 45); + Asi ^= Di; + BCu = ROL(Asi, 61); + Ega = BCa ^((~BCe)& BCi ); + Ege = BCe ^((~BCi)& BCo ); + Egi = BCi ^((~BCo)& BCu ); + Ego = BCo ^((~BCu)& BCa ); + Egu = BCu ^((~BCa)& BCe ); + + Abe ^= De; + BCa = ROL(Abe, 1); + Agi ^= Di; + BCe = ROL(Agi, 6); + Ako ^= Do; + BCi = ROL(Ako, 25); + Amu ^= Du; + BCo = ROL(Amu, 8); + Asa ^= Da; + BCu = ROL(Asa, 18); + Eka = BCa ^((~BCe)& BCi ); + Eke = BCe ^((~BCi)& BCo ); + Eki = BCi ^((~BCo)& BCu ); + Eko = BCo ^((~BCu)& BCa ); + Eku = BCu ^((~BCa)& BCe ); + + Abu ^= Du; + BCa = ROL(Abu, 27); + Aga ^= Da; + BCe = ROL(Aga, 36); + Ake ^= De; + BCi = ROL(Ake, 10); + Ami ^= Di; + BCo = ROL(Ami, 15); + Aso ^= Do; + BCu = ROL(Aso, 56); + Ema = BCa ^((~BCe)& BCi ); + Eme = BCe ^((~BCi)& BCo ); + Emi = BCi ^((~BCo)& BCu ); + Emo = BCo ^((~BCu)& BCa ); + Emu = BCu ^((~BCa)& BCe ); + + Abi ^= Di; + BCa = ROL(Abi, 62); + Ago ^= Do; + BCe = ROL(Ago, 55); + Aku ^= Du; + BCi = ROL(Aku, 39); + Ama ^= Da; + BCo = ROL(Ama, 41); + Ase ^= De; + BCu = ROL(Ase, 2); + Esa = BCa ^((~BCe)& BCi ); + Ese = BCe ^((~BCi)& BCo ); + Esi = BCi ^((~BCo)& BCu ); + Eso = BCo ^((~BCu)& BCa ); + Esu = BCu ^((~BCa)& BCe ); + + // prepareTheta + BCa = Eba^Ega^Eka^Ema^Esa; + BCe = Ebe^Ege^Eke^Eme^Ese; + BCi = Ebi^Egi^Eki^Emi^Esi; + BCo = Ebo^Ego^Eko^Emo^Eso; + BCu = Ebu^Egu^Eku^Emu^Esu; + + //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) + Da = BCu^ROL(BCe, 1); + De = BCa^ROL(BCi, 1); + Di = BCe^ROL(BCo, 1); + Do = BCi^ROL(BCu, 1); + Du = BCo^ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = ROL(Ege, 44); + Eki ^= Di; + BCi = ROL(Eki, 43); + Emo ^= Do; + BCo = ROL(Emo, 21); + Esu ^= Du; + BCu = ROL(Esu, 14); + Aba = BCa ^((~BCe)& BCi ); + Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; + Abe = BCe ^((~BCi)& BCo ); + Abi = BCi ^((~BCo)& BCu ); + Abo = BCo ^((~BCu)& BCa ); + Abu = BCu ^((~BCa)& BCe ); + + Ebo ^= Do; + BCa = ROL(Ebo, 28); + Egu ^= Du; + BCe = ROL(Egu, 20); + Eka ^= Da; + BCi = ROL(Eka, 3); + Eme ^= De; + BCo = ROL(Eme, 45); + Esi ^= Di; + BCu = ROL(Esi, 61); + Aga = BCa ^((~BCe)& BCi ); + Age = BCe ^((~BCi)& BCo ); + Agi = BCi ^((~BCo)& BCu ); + Ago = BCo ^((~BCu)& BCa ); + Agu = BCu ^((~BCa)& BCe ); + + Ebe ^= De; + BCa = ROL(Ebe, 1); + Egi ^= Di; + BCe = ROL(Egi, 6); + Eko ^= Do; + BCi = ROL(Eko, 25); + Emu ^= Du; + BCo = ROL(Emu, 8); + Esa ^= Da; + BCu = ROL(Esa, 18); + Aka = BCa ^((~BCe)& BCi ); + Ake = BCe ^((~BCi)& BCo ); + Aki = BCi ^((~BCo)& BCu ); + Ako = BCo ^((~BCu)& BCa ); + Aku = BCu ^((~BCa)& BCe ); + + Ebu ^= Du; + BCa = ROL(Ebu, 27); + Ega ^= Da; + BCe = ROL(Ega, 36); + Eke ^= De; + BCi = ROL(Eke, 10); + Emi ^= Di; + BCo = ROL(Emi, 15); + Eso ^= Do; + BCu = ROL(Eso, 56); + Ama = BCa ^((~BCe)& BCi ); + Ame = BCe ^((~BCi)& BCo ); + Ami = BCi ^((~BCo)& BCu ); + Amo = BCo ^((~BCu)& BCa ); + Amu = BCu ^((~BCa)& BCe ); + + Ebi ^= Di; + BCa = ROL(Ebi, 62); + Ego ^= Do; + BCe = ROL(Ego, 55); + Eku ^= Du; + BCi = ROL(Eku, 39); + Ema ^= Da; + BCo = ROL(Ema, 41); + Ese ^= De; + BCu = ROL(Ese, 2); + Asa = BCa ^((~BCe)& BCi ); + Ase = BCe ^((~BCi)& BCo ); + Asi = BCi ^((~BCo)& BCu ); + Aso = BCo ^((~BCu)& BCa ); + Asu = BCu ^((~BCa)& BCe ); + } + + //copyToState(state, A) + state[ 0] = Aba; + state[ 1] = Abe; + state[ 2] = Abi; + state[ 3] = Abo; + state[ 4] = Abu; + state[ 5] = Aga; + state[ 6] = Age; + state[ 7] = Agi; + state[ 8] = Ago; + state[ 9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +/************************************************* +* Name: keccak_absorb +* +* Description: Absorb step of Keccak; +* non-incremental, starts by zeroeing the state. +* +* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) +* - const uint8_t *m: pointer to input to be absorbed into s +* - int32_t mlen: length of input in bytes +* - uint8_t p: domain-separation byte for different +* Keccak-derived functions +**************************************************/ +static void keccak_absorb(uint64_t *s, + uint32_t r, + const uint8_t *m, + int32_t mlen, + uint8_t p) +{ + uint32_t i; + uint8_t t[200]; + DBENCH_START(); + + /* Zero state */ + for(i = 0; i < 25; ++i) + s[i] = 0; + + while(mlen >= r) { + for(i = 0; i < r/8; ++i) + s[i] ^= load64(m + 8*i); + + KeccakF1600_StatePermute(s); + mlen -= r; + m += r; + } + + for(i = 0; i < r; ++i) + t[i] = 0; + for(i = 0; i < mlen; ++i) + t[i] = m[i]; + t[i] = p; + t[r-1] |= 128; + for(i = 0; i < r/8; ++i) + s[i] ^= load64(t + 8*i); + + DBENCH_STOP(*tshake); +} + +/************************************************* +* Name: keccak_squeezeblocks +* +* Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each. +* Modifies the state. Can be called multiple times to keep +* squeezing, i.e., is incremental. +* +* Arguments: - uint8_t *h: pointer to output blocks +* - int32_t int nblocks: number of blocks to be +* squeezed (written to h) +* - uint64_t *s: pointer to input/output Keccak state +* - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) +**************************************************/ +static void keccak_squeezeblocks(uint8_t *h, + int32_t nblocks, + uint64_t *s, + uint32_t r) +{ + uint32_t i; + DBENCH_START(); + + while(nblocks > 0) { + KeccakF1600_StatePermute(s); + for(i=0; i < (r >> 3); i++) { + store64(h + 8*i, s[i]); + } + h += r; + --nblocks; + } + + DBENCH_STOP(*tshake); +} + +/************************************************* +* Name: shake128_absorb +* +* Description: Absorb step of the SHAKE128 XOF. +* non-incremental, starts by zeroeing the state. +* +* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* - const uint8_t *input: pointer to input to be absorbed +* into s +* - int32_t inlen: length of input in bytes +**************************************************/ +void shake128_absorb(uint64_t *s, + const uint8_t *input, + int32_t inlen) +{ + keccak_absorb(s, SHAKE128_RATE, input, inlen, 0x1F); +} + +/************************************************* +* Name: shake128_squeezeblocks +* +* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of +* SHAKE128_RATE bytes each. Modifies the state. Can be called +* multiple times to keep squeezing, i.e., is incremental. +* +* Arguments: - uint8_t *output: pointer to output blocks +* - int32_t nblocks: number of blocks to be squeezed +* (written to output) +* - uint64_t *s: pointer to input/output Keccak state +**************************************************/ +void shake128_squeezeblocks(uint8_t *output, + int32_t nblocks, + uint64_t *s) +{ + keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE); +} + +/************************************************* +* Name: shake256_absorb +* +* Description: Absorb step of the SHAKE256 XOF. +* non-incremental, starts by zeroeing the state. +* +* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* - const uint8_t *input: pointer to input to be absorbed +* into s +* - int32_t inlen: length of input in bytes +**************************************************/ +void shake256_absorb(uint64_t *s, + const uint8_t *input, + int32_t inlen) +{ + keccak_absorb(s, SHAKE256_RATE, input, inlen, 0x1F); +} + +/************************************************* +* Name: shake256_squeezeblocks +* +* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of +* SHAKE256_RATE bytes each. Modifies the state. Can be called +* multiple times to keep squeezing, i.e., is incremental. +* +* Arguments: - uint8_t *output: pointer to output blocks +* - int32_t nblocks: number of blocks to be squeezed +* (written to output) +* - uint64_t *s: pointer to input/output Keccak state +**************************************************/ +void shake256_squeezeblocks(uint8_t *output, + int32_t nblocks, + uint64_t *s) +{ + keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE); +} + +/************************************************* +* Name: shake128 +* +* Description: SHAKE128 XOF with non-incremental API +* +* Arguments: - uint8_t *output: pointer to output +* - int32_t outlen: requested output length in bytes +* - const uint8_t *input: pointer to input +* - int32_t inlen: length of input in bytes +**************************************************/ +void shake128(uint8_t *output, + int32_t outlen, + const uint8_t *input, + int32_t inlen) +{ + uint32_t i,nblocks = outlen/SHAKE128_RATE; + uint8_t t[SHAKE128_RATE]; + uint64_t s[25]; + + shake128_absorb(s, input, inlen); + shake128_squeezeblocks(output, nblocks, s); + + output += nblocks*SHAKE128_RATE; + outlen -= nblocks*SHAKE128_RATE; + + if(outlen) { + shake128_squeezeblocks(t, 1, s); + for(i = 0; i < outlen; ++i) + output[i] = t[i]; + } +} + +/************************************************* +* Name: shake256 +* +* Description: SHAKE256 XOF with non-incremental API +* +* Arguments: - uint8_t *output: pointer to output +* - int32_t outlen: requested output length in bytes +* - const uint8_t *input: pointer to input +* - int32_t inlen: length of input in bytes +**************************************************/ +void shake256(uint8_t *output, + int32_t outlen, + const uint8_t *input, + int32_t inlen) +{ + uint32_t i,nblocks = outlen/SHAKE256_RATE; + uint8_t t[SHAKE256_RATE]; + uint64_t s[25]; + + shake256_absorb(s, input, inlen); + shake256_squeezeblocks(output, nblocks, s); + + output += nblocks*SHAKE256_RATE; + outlen -= nblocks*SHAKE256_RATE; + + if(outlen) { + shake256_squeezeblocks(t, 1, s); + for(i = 0; i < outlen; ++i) + output[i] = t[i]; + } +} +//#include "params.h" +//#include "reduce.h" +//#include "ntt.h" +//#include "poly.h" + +/* Roots of unity in order needed by forward ntt */ +static const uint32_t zetas[N] = {0, 25847, 5771523, 7861508, 237124, 7602457, 7504169, 466468, 1826347, 2353451, 8021166, 6288512, 3119733, 5495562, 3111497, 2680103, 2725464, 1024112, 7300517, 3585928, 7830929, 7260833, 2619752, 6271868, 6262231, 4520680, 6980856, 5102745, 1757237, 8360995, 4010497, 280005, 2706023, 95776, 3077325, 3530437, 6718724, 4788269, 5842901, 3915439, 4519302, 5336701, 3574422, 5512770, 3539968, 8079950, 2348700, 7841118, 6681150, 6736599, 3505694, 4558682, 3507263, 6239768, 6779997, 3699596, 811944, 531354, 954230, 3881043, 3900724, 5823537, 2071892, 5582638, 4450022, 6851714, 4702672, 5339162, 6927966, 3475950, 2176455, 6795196, 7122806, 1939314, 4296819, 7380215, 5190273, 5223087, 4747489, 126922, 3412210, 7396998, 2147896, 2715295, 5412772, 4686924, 7969390, 5903370, 7709315, 7151892, 8357436, 7072248, 7998430, 1349076, 1852771, 6949987, 5037034, 264944, 508951, 3097992, 44288, 7280319, 904516, 3958618, 4656075, 8371839, 1653064, 5130689, 2389356, 8169440, 759969, 7063561, 189548, 4827145, 3159746, 6529015, 5971092, 8202977, 1315589, 1341330, 1285669, 6795489, 7567685, 6940675, 5361315, 4499357, 4751448, 3839961, 2091667, 3407706, 2316500, 3817976, 5037939, 2244091, 5933984, 4817955, 266997, 2434439, 7144689, 3513181, 4860065, 4621053, 7183191, 5187039, 900702, 1859098, 909542, 819034, 495491, 6767243, 8337157, 7857917, 7725090, 5257975, 2031748, 3207046, 4823422, 7855319, 7611795, 4784579, 342297, 286988, 5942594, 4108315, 3437287, 5038140, 1735879, 203044, 2842341, 2691481, 5790267, 1265009, 4055324, 1247620, 2486353, 1595974, 4613401, 1250494, 2635921, 4832145, 5386378, 1869119, 1903435, 7329447, 7047359, 1237275, 5062207, 6950192, 7929317, 1312455, 3306115, 6417775, 7100756, 1917081, 5834105, 7005614, 1500165, 777191, 2235880, 3406031, 7838005, 5548557, 6709241, 6533464, 5796124, 4656147, 594136, 4603424, 6366809, 2432395, 2454455, 8215696, 1957272, 3369112, 185531, 7173032, 5196991, 162844, 1616392, 3014001, 810149, 1652634, 4686184, 6581310, 5341501, 3523897, 3866901, 269760, 2213111, 7404533, 1717735, 472078, 7953734, 1723600, 6577327, 1910376, 6712985, 7276084, 8119771, 4546524, 5441381, 6144432, 7959518, 6094090, 183443, 7403526, 1612842, 4834730, 7826001, 3919660, 8332111, 7018208, 3937738, 1400424, 7534263, 1976782}; + +/* Roots of unity in order needed by inverse ntt */ +static const uint32_t zetas_inv[N] = {6403635, 846154, 6979993, 4442679, 1362209, 48306, 4460757, 554416, 3545687, 6767575, 976891, 8196974, 2286327, 420899, 2235985, 2939036, 3833893, 260646, 1104333, 1667432, 6470041, 1803090, 6656817, 426683, 7908339, 6662682, 975884, 6167306, 8110657, 4513516, 4856520, 3038916, 1799107, 3694233, 6727783, 7570268, 5366416, 6764025, 8217573, 3183426, 1207385, 8194886, 5011305, 6423145, 164721, 5925962, 5948022, 2013608, 3776993, 7786281, 3724270, 2584293, 1846953, 1671176, 2831860, 542412, 4974386, 6144537, 7603226, 6880252, 1374803, 2546312, 6463336, 1279661, 1962642, 5074302, 7067962, 451100, 1430225, 3318210, 7143142, 1333058, 1050970, 6476982, 6511298, 2994039, 3548272, 5744496, 7129923, 3767016, 6784443, 5894064, 7132797, 4325093, 7115408, 2590150, 5688936, 5538076, 8177373, 6644538, 3342277, 4943130, 4272102, 2437823, 8093429, 8038120, 3595838, 768622, 525098, 3556995, 5173371, 6348669, 3122442, 655327, 522500, 43260, 1613174, 7884926, 7561383, 7470875, 6521319, 7479715, 3193378, 1197226, 3759364, 3520352, 4867236, 1235728, 5945978, 8113420, 3562462, 2446433, 6136326, 3342478, 4562441, 6063917, 4972711, 6288750, 4540456, 3628969, 3881060, 3019102, 1439742, 812732, 1584928, 7094748, 7039087, 7064828, 177440, 2409325, 1851402, 5220671, 3553272, 8190869, 1316856, 7620448, 210977, 5991061, 3249728, 6727353, 8578, 3724342, 4421799, 7475901, 1100098, 8336129, 5282425, 7871466, 8115473, 3343383, 1430430, 6527646, 7031341, 381987, 1308169, 22981, 1228525, 671102, 2477047, 411027, 3693493, 2967645, 5665122, 6232521, 983419, 4968207, 8253495, 3632928, 3157330, 3190144, 1000202, 4083598, 6441103, 1257611, 1585221, 6203962, 4904467, 1452451, 3041255, 3677745, 1528703, 3930395, 2797779, 6308525, 2556880, 4479693, 4499374, 7426187, 7849063, 7568473, 4680821, 1600420, 2140649, 4873154, 3821735, 4874723, 1643818, 1699267, 539299, 6031717, 300467, 4840449, 2867647, 4805995, 3043716, 3861115, 4464978, 2537516, 3592148, 1661693, 4849980, 5303092, 8284641, 5674394, 8100412, 4369920, 19422, 6623180, 3277672, 1399561, 3859737, 2118186, 2108549, 5760665, 1119584, 549488, 4794489, 1079900, 7356305, 5654953, 5700314, 5268920, 2884855, 5260684, 2091905, 359251, 6026966, 6554070, 7913949, 876248, 777960, 8143293, 518909, 2608894, 8354570}; + +/************************************************* +* Name: ntt +* +* Description: Forward NTT, in-place. No modular reduction is performed after +* additions or subtractions. Hence output coefficients can be up +* to 16*Q larger than the coefficients of the input polynomial. +* Output vector is in bitreversed order. +* +* Arguments: - uint32_t p[N]: input/output coefficient array +**************************************************/ +void ntt(uint32_t p[N]) { + uint32_t len, start, j, k; + uint32_t zeta, t; + + k = 1; + for(len = 128; len > 0; len >>= 1) { + for(start = 0; start < N; start = j + len) { + zeta = zetas[k++]; + for(j = start; j < start + len; ++j) { + t = montgomery_reduce((uint64_t)zeta * p[j + len]); + p[j + len] = p[j] + 2*Q - t; + p[j] = p[j] + t; + } + } + } +} + +/************************************************* +* Name: invntt_frominvmont +* +* Description: Inverse NTT and multiplication by Montgomery factor 2^32. +* In-place. No modular reductions after additions or +* subtractions. Input coefficient need to be smaller than 2*Q. +* Output coefficient are smaller than 2*Q. +* +* Arguments: - uint32_t p[N]: input/output coefficient array +**************************************************/ +void invntt_frominvmont(uint32_t p[N]) { + uint32_t start, len, j, k; + uint32_t t, zeta; + const uint32_t f = (((uint64_t)MONT*MONT % Q) * (Q-1) % Q) * ((Q-1) >> 8) % Q; + + k = 0; + for(len = 1; len < N; len <<= 1) { + for(start = 0; start < N; start = j + len) { + zeta = zetas_inv[k++]; + for(j = start; j < start + len; ++j) { + t = p[j]; + p[j] = t + p[j + len]; + p[j + len] = t + 256*Q - p[j + len]; + p[j + len] = montgomery_reduce((uint64_t)zeta * p[j + len]); + } + } + } + + for(j = 0; j < N; ++j) { + p[j] = montgomery_reduce((uint64_t)f * p[j]); + } +} +//#include "params.h" +//#include "poly.h" +//#include "polyvec.h" +//#include "packing.h" + +/************************************************* +* Name: pack_pk +* +* Description: Bit-pack public key pk = (rho, t1). +* +* Arguments: - uint8_t pk[]: output byte array +* - const uint8_t rho[]: byte array containing rho +* - const polyveck *t1: pointer to vector t1 +**************************************************/ +void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[SEEDBYTES], + const polyveck *t1) +{ + uint32_t i; + + for(i = 0; i < SEEDBYTES; ++i) + pk[i] = rho[i]; + pk += SEEDBYTES; + + for(i = 0; i < K; ++i) + polyt1_pack(pk + i*POLT1_SIZE_PACKED, t1->vec+i); +} + +/************************************************* +* Name: unpack_pk +* +* Description: Unpack public key pk = (rho, t1). +* +* Arguments: - const uint8_t rho[]: output byte array for rho +* - const polyveck *t1: pointer to output vector t1 +* - uint8_t pk[]: byte array containing bit-packed pk +**************************************************/ +void unpack_pk(uint8_t rho[SEEDBYTES], + polyveck *t1, + const uint8_t pk[CRYPTO_PUBLICKEYBYTES]) +{ + uint32_t i; + + for(i = 0; i < SEEDBYTES; ++i) + rho[i] = pk[i]; + pk += SEEDBYTES; + + for(i = 0; i < K; ++i) + polyt1_unpack(t1->vec+i, pk + i*POLT1_SIZE_PACKED); +} + +/************************************************* +* Name: pack_sk +* +* Description: Bit-pack secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - uint8_t sk[]: output byte array +* - const uint8_t rho[]: byte array containing rho +* - const uint8_t key[]: byte array containing key +* - const uint8_t tr[]: byte array containing tr +* - const polyvecl *s1: pointer to vector s1 +* - const polyveck *s2: pointer to vector s2 +* - const polyveck *t0: pointer to vector t0 +**************************************************/ +void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], + const uint8_t rho[SEEDBYTES], + const uint8_t key[SEEDBYTES], + const uint8_t tr[CRHBYTES], + const polyvecl *s1, + const polyveck *s2, + const polyveck *t0) +{ + uint32_t i; + + for(i = 0; i < SEEDBYTES; ++i) + sk[i] = rho[i]; + sk += SEEDBYTES; + + for(i = 0; i < SEEDBYTES; ++i) + sk[i] = key[i]; + sk += SEEDBYTES; + + for(i = 0; i < CRHBYTES; ++i) + sk[i] = tr[i]; + sk += CRHBYTES; + + for(i = 0; i < L; ++i) + polyeta_pack(sk + i*POLETA_SIZE_PACKED, s1->vec+i); + sk += L*POLETA_SIZE_PACKED; + + for(i = 0; i < K; ++i) + polyeta_pack(sk + i*POLETA_SIZE_PACKED, s2->vec+i); + sk += K*POLETA_SIZE_PACKED; + + for(i = 0; i < K; ++i) + polyt0_pack(sk + i*POLT0_SIZE_PACKED, t0->vec+i); +} + +/************************************************* +* Name: unpack_sk +* +* Description: Unpack secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - const uint8_t rho[]: output byte array for rho +* - const uint8_t key[]: output byte array for key +* - const uint8_t tr[]: output byte array for tr +* - const polyvecl *s1: pointer to output vector s1 +* - const polyveck *s2: pointer to output vector s2 +* - const polyveck *r0: pointer to output vector t0 +* - uint8_t sk[]: byte array containing bit-packed sk +**************************************************/ +void unpack_sk(uint8_t rho[SEEDBYTES], + uint8_t key[SEEDBYTES], + uint8_t tr[CRHBYTES], + polyvecl *s1, + polyveck *s2, + polyveck *t0, + const uint8_t sk[CRYPTO_SECRETKEYBYTES]) +{ + uint32_t i; + + for(i = 0; i < SEEDBYTES; ++i) + rho[i] = sk[i]; + sk += SEEDBYTES; + + for(i = 0; i < SEEDBYTES; ++i) + key[i] = sk[i]; + sk += SEEDBYTES; + + for(i = 0; i < CRHBYTES; ++i) + tr[i] = sk[i]; + sk += CRHBYTES; + + for(i=0; i < L; ++i) + polyeta_unpack(s1->vec+i, sk + i*POLETA_SIZE_PACKED); + sk += L*POLETA_SIZE_PACKED; + + for(i=0; i < K; ++i) + polyeta_unpack(s2->vec+i, sk + i*POLETA_SIZE_PACKED); + sk += K*POLETA_SIZE_PACKED; + + for(i=0; i < K; ++i) + polyt0_unpack(t0->vec+i, sk + i*POLT0_SIZE_PACKED); +} + +/************************************************* +* Name: pack_sig +* +* Description: Bit-pack signature sig = (z, h, c). +* +* Arguments: - uint8_t sig[]: output byte array +* - const polyvecl *z: pointer to vector z +* - const polyveck *h: pointer to hint vector h +* - const poly *c: pointer to challenge polynomial +**************************************************/ +void pack_sig(uint8_t sig[CRYPTO_BYTES], + const polyvecl *z, + const polyveck *h, + const poly *c) +{ + uint32_t i, j, k; + uint64_t signs, mask; + + for(i = 0; i < L; ++i) + polyz_pack(sig + i*POLZ_SIZE_PACKED, z->vec+i); + sig += L*POLZ_SIZE_PACKED; + + /* Encode h */ + k = 0; + for(i = 0; i < K; ++i) { + for(j = 0; j < N; ++j) + if(h->vec[i].coeffs[j] != 0) + sig[k++] = j; + + sig[OMEGA + i] = k; + } + while(k < OMEGA) sig[k++] = 0; + sig += OMEGA + K; + + /* Encode c */ + signs = 0; + mask = 1; + for(i = 0; i < N/8; ++i) { + sig[i] = 0; + for(j = 0; j < 8; ++j) { + if(c->coeffs[8*i+j] != 0) { + sig[i] |= (1U << j); + if(c->coeffs[8*i+j] == (Q - 1)) signs |= mask; + mask <<= 1; + } + } + } + sig += N/8; + for(i = 0; i < 8; ++i) + sig[i] = signs >> 8*i; +} + +/************************************************* +* Name: unpack_sig +* +* Description: Unpack signature sig = (z, h, c). +* +* Arguments: - polyvecl *z: pointer to output vector z +* - polyveck *h: pointer to output hint vector h +* - poly *c: pointer to output challenge polynomial +* - const uint8_t sig[]: byte array containing +* bit-packed signature +* +* Returns 1 in case of malformed signature; otherwise 0. +**************************************************/ +int unpack_sig(polyvecl *z, + polyveck *h, + poly *c, + const uint8_t sig[CRYPTO_BYTES]) +{ + uint32_t i, j, k; + uint64_t signs, mask; + + for(i = 0; i < L; ++i) + polyz_unpack(z->vec+i, sig + i*POLZ_SIZE_PACKED); + sig += L*POLZ_SIZE_PACKED; + + /* Decode h */ + k = 0; + for(i = 0; i < K; ++i) { + for(j = 0; j < N; ++j) + h->vec[i].coeffs[j] = 0; + + if(sig[OMEGA + i] < k || sig[OMEGA + i] > OMEGA) + return 1; + + for(j = k; j < sig[OMEGA + i]; ++j) { + /* Coefficients are ordered for strong unforgeability */ + if(j > k && sig[j] <= sig[j-1]) return 1; + h->vec[i].coeffs[sig[j]] = 1; + } + + k = sig[OMEGA + i]; + } + + /* Extra indices are zero for strong unforgeability */ + for(j = k; j < OMEGA; ++j) + if(sig[j]) + return 1; + + sig += OMEGA + K; + + /* Decode c */ + for(i = 0; i < N; ++i) + c->coeffs[i] = 0; + + signs = 0; + for(i = 0; i < 8; ++i) + signs |= (uint64_t)sig[N/8+i] << 8*i; + + /* Extra sign bits are zero for strong unforgeability */ + if(signs >> 60) + return 1; + + mask = 1; + for(i = 0; i < N/8; ++i) { + for(j = 0; j < 8; ++j) { + if((sig[i] >> j) & 0x01) { + c->coeffs[8*i+j] = (signs & mask) ? Q - 1 : 1; + mask <<= 1; + } + } + } + + return 0; +} +//#include +//#include "test/cpucycles.h" +//#include "fips202.h" +//#include "params.h" +//#include "reduce.h" +//#include "rounding.h" +//#include "ntt.h" +//#include "poly.h" + +#ifdef DBENCH +extern const uint64_t timing_overhead; +extern uint64_t *tred, *tadd, *tmul, *tround, *tsample, *tpack; +#endif + +/************************************************* +* Name: poly_reduce +* +* Description: Reduce all coefficients of input polynomial to representative +* in [0,2*Q[. +* +* Arguments: - poly *a: pointer to input/output polynomial +**************************************************/ +void poly_reduce(poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a->coeffs[i] = reduce32(a->coeffs[i]); + + DBENCH_STOP(*tred); +} + +/************************************************* +* Name: poly_csubq +* +* Description: For all coefficients of input polynomial subtract Q if +* coefficient is bigger than Q. +* +* Arguments: - poly *a: pointer to input/output polynomial +**************************************************/ +void poly_csubq(poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a->coeffs[i] = csubq(a->coeffs[i]); + + DBENCH_STOP(*tred); +} + +/************************************************* +* Name: poly_freeze +* +* Description: Reduce all coefficients of the polynomial to standard +* representatives. +* +* Arguments: - poly *a: pointer to input/output polynomial +**************************************************/ +void poly_freeze(poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a->coeffs[i] = freeze(a->coeffs[i]); + + DBENCH_STOP(*tred); +} + +/************************************************* +* Name: poly_add +* +* Description: Add polynomials. No modular reduction is performed. +* +* Arguments: - poly *c: pointer to output polynomial +* - const poly *a: pointer to first summand +* - const poly *b: pointer to second summand +**************************************************/ +void poly_add(poly *c, const poly *a, const poly *b) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + c->coeffs[i] = a->coeffs[i] + b->coeffs[i]; + + DBENCH_STOP(*tadd); +} + +/************************************************* +* Name: poly_sub +* +* Description: Subtract polynomials. Assumes coefficients of second input +* polynomial to be less than 2*Q. No modular reduction is +* performed. +* +* Arguments: - poly *c: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial to be +* subtraced from first input polynomial +**************************************************/ +void poly_sub(poly *c, const poly *a, const poly *b) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + c->coeffs[i] = a->coeffs[i] + 2*Q - b->coeffs[i]; + + DBENCH_STOP(*tadd); +} + +/************************************************* +* Name: poly_neg +* +* Description: Negate polynomial. Assumes input coefficients to be standard +* representatives. +* +* Arguments: - poly *a: pointer to input/output polynomial +**************************************************/ +void poly_neg(poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a->coeffs[i] = Q - a->coeffs[i]; + + DBENCH_STOP(*tadd); +} + +/************************************************* +* Name: poly_shiftl +* +* Description: Multiply polynomial by 2^k without modular reduction. Assumes +* input coefficients to be less than 2^{32-k}. +* +* Arguments: - poly *a: pointer to input/output polynomial +* - uint32_t k: exponent +**************************************************/ +void poly_shiftl(poly *a, uint32_t k) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a->coeffs[i] <<= k; + + DBENCH_STOP(*tmul); +} + +/************************************************* +* Name: poly_ntt +* +* Description: Forward NTT. Output coefficients can be up to 16*Q larger than +* input coefficients. +* +* Arguments: - poly *a: pointer to input/output polynomial +**************************************************/ +void poly_ntt(poly *a) { + DBENCH_START(); + + ntt(a->coeffs); + + DBENCH_STOP(*tmul); +} + +/************************************************* +* Name: poly_invntt_montgomery +* +* Description: Inverse NTT and multiplication with 2^{32}. Input coefficients +* need to be less than 2*Q. Output coefficients are less than 2*Q. +* +* Arguments: - poly *a: pointer to input/output polynomial +**************************************************/ +void poly_invntt_montgomery(poly *a) { + DBENCH_START(); + + invntt_frominvmont(a->coeffs); + + DBENCH_STOP(*tmul); +} + +/************************************************* +* Name: poly_pointwise_invmontgomery +* +* Description: Pointwise multiplication of polynomials in NTT domain +* representation and multiplication of resulting polynomial +* with 2^{-32}. Output coefficients are less than 2*Q if input +* coefficient are less than 22*Q. +* +* Arguments: - poly *c: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + c->coeffs[i] = montgomery_reduce((uint64_t)a->coeffs[i] * b->coeffs[i]); + + DBENCH_STOP(*tmul); +} + +/************************************************* +* Name: poly_power2round +* +* Description: For all coefficients c of the input polynomial, +* compute c0, c1 such that c mod Q = c1*2^D + c0 +* with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients to be +* standard representatives. +* +* Arguments: - poly *a1: pointer to output polynomial with coefficients c1 +* - poly *a0: pointer to output polynomial with coefficients Q + a0 +* - const poly *v: pointer to input polynomial +**************************************************/ +void poly_power2round(poly *a1, poly *a0, const poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a1->coeffs[i] = power2round(a->coeffs[i], a0->coeffs+i); + + DBENCH_STOP(*tround); +} + +/************************************************* +* Name: poly_decompose +* +* Description: For all coefficients c of the input polynomial, +* compute high and low bits c0, c1 such c mod Q = c1*ALPHA + c0 +* with -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA where we +* set c1 = 0 and -ALPHA/2 <= c0 = c mod Q - Q < 0. +* Assumes coefficients to be standard representatives. +* +* Arguments: - poly *a1: pointer to output polynomial with coefficients c1 +* - poly *a0: pointer to output polynomial with coefficients Q + a0 +* - const poly *c: pointer to input polynomial +**************************************************/ +void poly_decompose(poly *a1, poly *a0, const poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a1->coeffs[i] = decompose(a->coeffs[i], a0->coeffs+i); + + DBENCH_STOP(*tround); +} + +/************************************************* +* Name: poly_make_hint +* +* Description: Compute hint polynomial. The coefficients of which indicate +* whether the high bits of the corresponding coefficients +* of the first input polynomial and of the sum of the input +* polynomials differ. +* +* Arguments: - poly *h: pointer to output hint polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +* +* Returns number of 1 bits. +**************************************************/ +uint32_t poly_make_hint(poly *h, const poly *a, const poly *b) { + uint32_t i, s = 0; + DBENCH_START(); + + for(i = 0; i < N; ++i) { + h->coeffs[i] = make_hint(a->coeffs[i], b->coeffs[i]); + s += h->coeffs[i]; + } + + DBENCH_STOP(*tround); + return s; +} + +/************************************************* +* Name: poly_use_hint +* +* Description: Use hint polynomial to correct the high bits of a polynomial. +* +* Arguments: - poly *a: pointer to output polynomial with corrected high bits +* - const poly *b: pointer to input polynomial +* - const poly *h: pointer to input hint polynomial +**************************************************/ +void poly_use_hint(poly *a, const poly *b, const poly *h) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N; ++i) + a->coeffs[i] = use_hint(b->coeffs[i], h->coeffs[i]); + + DBENCH_STOP(*tround); +} + +/************************************************* +* Name: poly_chknorm +* +* Description: Check infinity norm of polynomial against given bound. +* Assumes input coefficients to be standard representatives. +* +* Arguments: - const poly *a: pointer to polynomial +* - uint32_t B: norm bound +* +* Returns 0 if norm is strictly smaller than B and 1 otherwise. +**************************************************/ +int poly_chknorm(const poly *a, uint32_t B) { + uint32_t i; + int32_t t; + DBENCH_START(); + + /* It is ok to leak which coefficient violates the bound since + the probability for each coefficient is independent of secret + data but we must not leak the sign of the centralized representative. */ + for(i = 0; i < N; ++i) { + /* Absolute value of centralized representative */ + t = (Q-1)/2 - a->coeffs[i]; + t ^= (t >> 31); + t = (Q-1)/2 - t; + + if((uint32_t)t >= B) { + DBENCH_STOP(*tsample); + return 1; + } + } + + DBENCH_STOP(*tsample); + return 0; +} + +/************************************************* +* Name: poly_uniform +* +* Description: Sample uniformly random polynomial using stream of random bytes. +* Assumes that enough random bytes are given (e.g. +* 5*SHAKE128_RATE bytes). +* +* Arguments: - poly *a: pointer to output polynomial +* - const uint8_t *buf: array of random bytes +**************************************************/ +void poly_uniform(poly *a, const uint8_t *buf) { + uint32_t ctr, pos; + uint32_t t; + DBENCH_START(); + + ctr = pos = 0; + while(ctr < N) { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if(t < Q) + a->coeffs[ctr++] = t; + } + + DBENCH_STOP(*tsample); +} + +/************************************************* +* Name: rej_eta +* +* Description: Sample uniformly random coefficients in [-ETA, ETA] by +* performing rejection sampling using array of random bytes. +* +* Arguments: - uint32_t *a: pointer to output array (allocated) +* - uint32_t len: number of coefficients to be sampled +* - const uint8_t *buf: array of random bytes +* - uint32_t buflen: length of array of random bytes +* +* Returns number of sampled coefficients. Can be smaller than len if not enough +* random bytes were given. +**************************************************/ +static uint32_t rej_eta(uint32_t *a, + uint32_t len, + const uint8_t *buf, + uint32_t buflen) +{ +#if ETA > 7 +#error "rej_eta() assumes ETA <= 7" +#endif + uint32_t ctr, pos; + uint8_t t0, t1; + DBENCH_START(); + + ctr = pos = 0; + while(ctr < len && pos < buflen) { +#if ETA <= 3 + t0 = buf[pos] & 0x07; + t1 = buf[pos++] >> 5; +#else + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; +#endif + + if(t0 <= 2*ETA) + a[ctr++] = Q + ETA - t0; + if(t1 <= 2*ETA && ctr < len) + a[ctr++] = Q + ETA - t1; + } + + DBENCH_STOP(*tsample); + return ctr; +} + +/************************************************* +* Name: poly_uniform_eta +* +* Description: Sample polynomial with uniformly random coefficients +* in [-ETA,ETA] by performing rejection sampling using the +* output stream from SHAKE256(seed|nonce). +* +* Arguments: - poly *a: pointer to output polynomial +* - const uint8_t seed[]: byte array with seed of length +* SEEDBYTES +* - uint8_t nonce: nonce byte +**************************************************/ +void poly_uniform_eta(poly *a, + const uint8_t seed[SEEDBYTES], + uint8_t nonce) +{ + uint32_t i, ctr; + uint8_t inbuf[SEEDBYTES + 1]; + /* Probability that we need more than 2 blocks: < 2^{-84} + Probability that we need more than 3 blocks: < 2^{-352} */ + uint8_t outbuf[2*SHAKE256_RATE]; + uint64_t state[25]; + + for(i= 0; i < SEEDBYTES; ++i) + inbuf[i] = seed[i]; + inbuf[SEEDBYTES] = nonce; + + shake256_absorb(state, inbuf, SEEDBYTES + 1); + shake256_squeezeblocks(outbuf, 2, state); + + ctr = rej_eta(a->coeffs, N, outbuf, 2*SHAKE256_RATE); + if(ctr < N) { + shake256_squeezeblocks(outbuf, 1, state); + rej_eta(a->coeffs + ctr, N - ctr, outbuf, SHAKE256_RATE); + } +} + +/************************************************* +* Name: rej_gamma1m1 +* +* Description: Sample uniformly random coefficients +* in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection sampling +* using array of random bytes. +* +* Arguments: - uint32_t *a: pointer to output array (allocated) +* - uint32_t len: number of coefficients to be sampled +* - const uint8_t *buf: array of random bytes +* - uint32_t buflen: length of array of random bytes +* +* Returns number of sampled coefficients. Can be smaller than len if not enough +* random bytes were given. +**************************************************/ +static uint32_t rej_gamma1m1(uint32_t *a, + uint32_t len, + const uint8_t *buf, + uint32_t buflen) +{ +#if GAMMA1 > (1 << 19) +#error "rej_gamma1m1() assumes GAMMA1 - 1 fits in 19 bits" +#endif + uint32_t ctr, pos; + uint32_t t0, t1; + DBENCH_START(); + + ctr = pos = 0; + while(ctr < len && pos + 5 <= buflen) { + t0 = buf[pos]; + t0 |= (uint32_t)buf[pos + 1] << 8; + t0 |= (uint32_t)buf[pos + 2] << 16; + t0 &= 0xFFFFF; + + t1 = buf[pos + 2] >> 4; + t1 |= (uint32_t)buf[pos + 3] << 4; + t1 |= (uint32_t)buf[pos + 4] << 12; + + pos += 5; + + if(t0 <= 2*GAMMA1 - 2) + a[ctr++] = Q + GAMMA1 - 1 - t0; + if(t1 <= 2*GAMMA1 - 2 && ctr < len) + a[ctr++] = Q + GAMMA1 - 1 - t1; + } + + DBENCH_STOP(*tsample); + return ctr; +} + +/************************************************* +* Name: poly_uniform_gamma1m1 +* +* Description: Sample polynomial with uniformly random coefficients +* in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection +* sampling on output stream of SHAKE256(seed|nonce). +* +* Arguments: - poly *a: pointer to output polynomial +* - const uint8_t seed[]: byte array with seed of length +* SEEDBYTES + CRHBYTES +* - uint16_t nonce: 16-bit nonce +**************************************************/ +void poly_uniform_gamma1m1(poly *a, + const uint8_t seed[SEEDBYTES + CRHBYTES], + uint16_t nonce) +{ + uint32_t i, ctr; + uint8_t inbuf[SEEDBYTES + CRHBYTES + 2]; + /* Probability that we need more than 5 blocks: < 2^{-81} + Probability that we need more than 6 blocks: < 2^{-467} */ + uint8_t outbuf[5*SHAKE256_RATE]; + uint64_t state[25]; + + for(i = 0; i < SEEDBYTES + CRHBYTES; ++i) + inbuf[i] = seed[i]; + inbuf[SEEDBYTES + CRHBYTES] = nonce & 0xFF; + inbuf[SEEDBYTES + CRHBYTES + 1] = nonce >> 8; + + shake256_absorb(state, inbuf, SEEDBYTES + CRHBYTES + 2); + shake256_squeezeblocks(outbuf, 5, state); + + ctr = rej_gamma1m1(a->coeffs, N, outbuf, 5*SHAKE256_RATE); + if(ctr < N) { + /* There are no bytes left in outbuf + since 5*SHAKE256_RATE is divisible by 5 */ + shake256_squeezeblocks(outbuf, 1, state); + rej_gamma1m1(a->coeffs + ctr, N - ctr, outbuf, SHAKE256_RATE); + } +} + +/************************************************* +* Name: polyeta_pack +* +* Description: Bit-pack polynomial with coefficients in [-ETA,ETA]. +* Input coefficients are assumed to lie in [Q-ETA,Q+ETA]. +* +* Arguments: - uint8_t *r: pointer to output byte array with at least +* POLETA_SIZE_PACKED bytes +* - const poly *a: pointer to input polynomial +**************************************************/ +void polyeta_pack(uint8_t *r, const poly *a) { +#if ETA > 7 +#error "polyeta_pack() assumes ETA <= 7" +#endif + uint32_t i; + uint8_t t[8]; + DBENCH_START(); + +#if ETA <= 3 + for(i = 0; i < N/8; ++i) { + t[0] = Q + ETA - a->coeffs[8*i+0]; + t[1] = Q + ETA - a->coeffs[8*i+1]; + t[2] = Q + ETA - a->coeffs[8*i+2]; + t[3] = Q + ETA - a->coeffs[8*i+3]; + t[4] = Q + ETA - a->coeffs[8*i+4]; + t[5] = Q + ETA - a->coeffs[8*i+5]; + t[6] = Q + ETA - a->coeffs[8*i+6]; + t[7] = Q + ETA - a->coeffs[8*i+7]; + + r[3*i+0] = t[0]; + r[3*i+0] |= t[1] << 3; + r[3*i+0] |= t[2] << 6; + r[3*i+1] = t[2] >> 2; + r[3*i+1] |= t[3] << 1; + r[3*i+1] |= t[4] << 4; + r[3*i+1] |= t[5] << 7; + r[3*i+2] = t[5] >> 1; + r[3*i+2] |= t[6] << 2; + r[3*i+2] |= t[7] << 5; + } +#else + for(i = 0; i < N/2; ++i) { + t[0] = Q + ETA - a->coeffs[2*i+0]; + t[1] = Q + ETA - a->coeffs[2*i+1]; + r[i] = t[0] | (t[1] << 4); + } +#endif + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyeta_unpack +* +* Description: Unpack polynomial with coefficients in [-ETA,ETA]. +* Output coefficients lie in [Q-ETA,Q+ETA]. +* +* Arguments: - poly *r: pointer to output polynomial +* - const uint8_t *a: byte array with bit-packed polynomial +**************************************************/ +void polyeta_unpack(poly *r, const uint8_t *a) { + uint32_t i; + DBENCH_START(); + +#if ETA <= 3 + for(i = 0; i < N/8; ++i) { + r->coeffs[8*i+0] = a[3*i+0] & 0x07; + r->coeffs[8*i+1] = (a[3*i+0] >> 3) & 0x07; + r->coeffs[8*i+2] = (a[3*i+0] >> 6) | ((a[3*i+1] & 0x01) << 2); + r->coeffs[8*i+3] = (a[3*i+1] >> 1) & 0x07; + r->coeffs[8*i+4] = (a[3*i+1] >> 4) & 0x07; + r->coeffs[8*i+5] = (a[3*i+1] >> 7) | ((a[3*i+2] & 0x03) << 1); + r->coeffs[8*i+6] = (a[3*i+2] >> 2) & 0x07; + r->coeffs[8*i+7] = (a[3*i+2] >> 5); + + r->coeffs[8*i+0] = Q + ETA - r->coeffs[8*i+0]; + r->coeffs[8*i+1] = Q + ETA - r->coeffs[8*i+1]; + r->coeffs[8*i+2] = Q + ETA - r->coeffs[8*i+2]; + r->coeffs[8*i+3] = Q + ETA - r->coeffs[8*i+3]; + r->coeffs[8*i+4] = Q + ETA - r->coeffs[8*i+4]; + r->coeffs[8*i+5] = Q + ETA - r->coeffs[8*i+5]; + r->coeffs[8*i+6] = Q + ETA - r->coeffs[8*i+6]; + r->coeffs[8*i+7] = Q + ETA - r->coeffs[8*i+7]; + } +#else + for(i = 0; i < N/2; ++i) { + r->coeffs[2*i+0] = a[i] & 0x0F; + r->coeffs[2*i+1] = a[i] >> 4; + r->coeffs[2*i+0] = Q + ETA - r->coeffs[2*i+0]; + r->coeffs[2*i+1] = Q + ETA - r->coeffs[2*i+1]; + } +#endif + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyt1_pack +* +* Description: Bit-pack polynomial t1 with coefficients fitting in 9 bits. +* Input coefficients are assumed to be standard representatives. +* +* Arguments: - uint8_t *r: pointer to output byte array with at least +* POLT1_SIZE_PACKED bytes +* - const poly *a: pointer to input polynomial +**************************************************/ +void polyt1_pack(uint8_t *r, const poly *a) { +#if D != 14 +#error "polyt1_pack() assumes D == 14" +#endif + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N/8; ++i) { + r[9*i+0] = a->coeffs[8*i+0] & 0xFF; + r[9*i+1] = (a->coeffs[8*i+0] >> 8) | ((a->coeffs[8*i+1] & 0x7F) << 1); + r[9*i+2] = (a->coeffs[8*i+1] >> 7) | ((a->coeffs[8*i+2] & 0x3F) << 2); + r[9*i+3] = (a->coeffs[8*i+2] >> 6) | ((a->coeffs[8*i+3] & 0x1F) << 3); + r[9*i+4] = (a->coeffs[8*i+3] >> 5) | ((a->coeffs[8*i+4] & 0x0F) << 4); + r[9*i+5] = (a->coeffs[8*i+4] >> 4) | ((a->coeffs[8*i+5] & 0x07) << 5); + r[9*i+6] = (a->coeffs[8*i+5] >> 3) | ((a->coeffs[8*i+6] & 0x03) << 6); + r[9*i+7] = (a->coeffs[8*i+6] >> 2) | ((a->coeffs[8*i+7] & 0x01) << 7); + r[9*i+8] = a->coeffs[8*i+7] >> 1; + } + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyt1_unpack +* +* Description: Unpack polynomial t1 with 9-bit coefficients. +* Output coefficients are standard representatives. +* +* Arguments: - poly *r: pointer to output polynomial +* - const uint8_t *a: byte array with bit-packed polynomial +**************************************************/ +void polyt1_unpack(poly *r, const uint8_t *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N/8; ++i) { + r->coeffs[8*i+0] = a[9*i+0] | ((uint32_t)(a[9*i+1] & 0x01) << 8); + r->coeffs[8*i+1] = (a[9*i+1] >> 1) | ((uint32_t)(a[9*i+2] & 0x03) << 7); + r->coeffs[8*i+2] = (a[9*i+2] >> 2) | ((uint32_t)(a[9*i+3] & 0x07) << 6); + r->coeffs[8*i+3] = (a[9*i+3] >> 3) | ((uint32_t)(a[9*i+4] & 0x0F) << 5); + r->coeffs[8*i+4] = (a[9*i+4] >> 4) | ((uint32_t)(a[9*i+5] & 0x1F) << 4); + r->coeffs[8*i+5] = (a[9*i+5] >> 5) | ((uint32_t)(a[9*i+6] & 0x3F) << 3); + r->coeffs[8*i+6] = (a[9*i+6] >> 6) | ((uint32_t)(a[9*i+7] & 0x7F) << 2); + r->coeffs[8*i+7] = (a[9*i+7] >> 7) | ((uint32_t)(a[9*i+8] & 0xFF) << 1); + } + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyt0_pack +* +* Description: Bit-pack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}]. +* Input coefficients are assumed to lie in ]Q-2^{D-1}, Q+2^{D-1}]. +* +* Arguments: - uint8_t *r: pointer to output byte array with at least +* POLT0_SIZE_PACKED bytes +* - const poly *a: pointer to input polynomial +**************************************************/ +void polyt0_pack(uint8_t *r, const poly *a) { + uint32_t i; + uint32_t t[4]; + DBENCH_START(); + + for(i = 0; i < N/4; ++i) { + t[0] = Q + (1 << (D-1)) - a->coeffs[4*i+0]; + t[1] = Q + (1 << (D-1)) - a->coeffs[4*i+1]; + t[2] = Q + (1 << (D-1)) - a->coeffs[4*i+2]; + t[3] = Q + (1 << (D-1)) - a->coeffs[4*i+3]; + + r[7*i+0] = t[0]; + r[7*i+1] = t[0] >> 8; + r[7*i+1] |= t[1] << 6; + r[7*i+2] = t[1] >> 2; + r[7*i+3] = t[1] >> 10; + r[7*i+3] |= t[2] << 4; + r[7*i+4] = t[2] >> 4; + r[7*i+5] = t[2] >> 12; + r[7*i+5] |= t[3] << 2; + r[7*i+6] = t[3] >> 6; + } + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyt0_unpack +* +* Description: Unpack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}]. +* Output coefficients lie in ]Q-2^{D-1},Q+2^{D-1}]. +* +* Arguments: - poly *r: pointer to output polynomial +* - const uint8_t *a: byte array with bit-packed polynomial +**************************************************/ +void polyt0_unpack(poly *r, const uint8_t *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N/4; ++i) { + r->coeffs[4*i+0] = a[7*i+0]; + r->coeffs[4*i+0] |= (uint32_t)(a[7*i+1] & 0x3F) << 8; + + r->coeffs[4*i+1] = a[7*i+1] >> 6; + r->coeffs[4*i+1] |= (uint32_t)a[7*i+2] << 2; + r->coeffs[4*i+1] |= (uint32_t)(a[7*i+3] & 0x0F) << 10; + + r->coeffs[4*i+2] = a[7*i+3] >> 4; + r->coeffs[4*i+2] |= (uint32_t)a[7*i+4] << 4; + r->coeffs[4*i+2] |= (uint32_t)(a[7*i+5] & 0x03) << 12; + + r->coeffs[4*i+3] = a[7*i+5] >> 2; + r->coeffs[4*i+3] |= (uint32_t)a[7*i+6] << 6; + + r->coeffs[4*i+0] = Q + (1 << (D-1)) - r->coeffs[4*i+0]; + r->coeffs[4*i+1] = Q + (1 << (D-1)) - r->coeffs[4*i+1]; + r->coeffs[4*i+2] = Q + (1 << (D-1)) - r->coeffs[4*i+2]; + r->coeffs[4*i+3] = Q + (1 << (D-1)) - r->coeffs[4*i+3]; + } + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyz_pack +* +* Description: Bit-pack polynomial z with coefficients +* in [-(GAMMA1 - 1), GAMMA1 - 1]. +* Input coefficients are assumed to be standard representatives. +* +* Arguments: - uint8_t *r: pointer to output byte array with at least +* POLZ_SIZE_PACKED bytes +* - const poly *a: pointer to input polynomial +**************************************************/ +void polyz_pack(uint8_t *r, const poly *a) { +#if GAMMA1 > (1 << 19) +#error "polyz_pack() assumes GAMMA1 <= 2^{19}" +#endif + uint32_t i; + uint32_t t[2]; + DBENCH_START(); + + for(i = 0; i < N/2; ++i) { + /* Map to {0,...,2*GAMMA1 - 2} */ + t[0] = GAMMA1 - 1 - a->coeffs[2*i+0]; + t[0] += ((int32_t)t[0] >> 31) & Q; + t[1] = GAMMA1 - 1 - a->coeffs[2*i+1]; + t[1] += ((int32_t)t[1] >> 31) & Q; + + r[5*i+0] = t[0]; + r[5*i+1] = t[0] >> 8; + r[5*i+2] = t[0] >> 16; + r[5*i+2] |= t[1] << 4; + r[5*i+3] = t[1] >> 4; + r[5*i+4] = t[1] >> 12; + } + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyz_unpack +* +* Description: Unpack polynomial z with coefficients +* in [-(GAMMA1 - 1), GAMMA1 - 1]. +* Output coefficients are standard representatives. +* +* Arguments: - poly *r: pointer to output polynomial +* - const uint8_t *a: byte array with bit-packed polynomial +**************************************************/ +void polyz_unpack(poly *r, const uint8_t *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N/2; ++i) { + r->coeffs[2*i+0] = a[5*i+0]; + r->coeffs[2*i+0] |= (uint32_t)a[5*i+1] << 8; + r->coeffs[2*i+0] |= (uint32_t)(a[5*i+2] & 0x0F) << 16; + + r->coeffs[2*i+1] = a[5*i+2] >> 4; + r->coeffs[2*i+1] |= (uint32_t)a[5*i+3] << 4; + r->coeffs[2*i+1] |= (uint32_t)a[5*i+4] << 12; + + r->coeffs[2*i+0] = GAMMA1 - 1 - r->coeffs[2*i+0]; + r->coeffs[2*i+0] += ((int32_t)r->coeffs[2*i+0] >> 31) & Q; + r->coeffs[2*i+1] = GAMMA1 - 1 - r->coeffs[2*i+1]; + r->coeffs[2*i+1] += ((int32_t)r->coeffs[2*i+1] >> 31) & Q; + } + + DBENCH_STOP(*tpack); +} + +/************************************************* +* Name: polyw1_pack +* +* Description: Bit-pack polynomial w1 with coefficients in [0, 15]. +* Input coefficients are assumed to be standard representatives. +* +* Arguments: - uint8_t *r: pointer to output byte array with at least +* POLW1_SIZE_PACKED bytes +* - const poly *a: pointer to input polynomial +**************************************************/ +void polyw1_pack(uint8_t *r, const poly *a) { + uint32_t i; + DBENCH_START(); + + for(i = 0; i < N/2; ++i) + r[i] = a->coeffs[2*i+0] | (a->coeffs[2*i+1] << 4); + + DBENCH_STOP(*tpack); +} +//#include +//#include "params.h" +//#include "poly.h" +//#include "polyvec.h" + +/**************************************************************/ +/************ Vectors of polynomials of length L **************/ +/**************************************************************/ + +/************************************************* +* Name: polyvecl_freeze +* +* Description: Reduce coefficients of polynomials in vector of length L +* to standard representatives. +* +* Arguments: - polyvecl *v: pointer to input/output vector +**************************************************/ +void polyvecl_freeze(polyvecl *v) { + uint32_t i; + + for(i = 0; i < L; ++i) + poly_freeze(v->vec+i); +} + +/************************************************* +* Name: polyvecl_add +* +* Description: Add vectors of polynomials of length L. +* No modular reduction is performed. +* +* Arguments: - polyvecl *w: pointer to output vector +* - const polyvecl *u: pointer to first summand +* - const polyvecl *v: pointer to second summand +**************************************************/ +void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v) { + uint32_t i; + + for(i = 0; i < L; ++i) + poly_add(w->vec+i, u->vec+i, v->vec+i); +} + +/************************************************* +* Name: polyvecl_ntt +* +* Description: Forward NTT of all polynomials in vector of length L. Output +* coefficients can be up to 16*Q larger than input coefficients. +* +* Arguments: - polyvecl *v: pointer to input/output vector +**************************************************/ +void polyvecl_ntt(polyvecl *v) { + uint32_t i; + + for(i = 0; i < L; ++i) + poly_ntt(v->vec+i); +} + +/************************************************* +* Name: polyvecl_pointwise_acc_invmontgomery +* +* Description: Pointwise multiply vectors of polynomials of length L, multiply +* resulting vector by 2^{-32} and add (accumulate) polynomials +* in it. Input/output vectors are in NTT domain representation. +* Input coefficients are assumed to be less than 22*Q. Output +* coeffcient are less than 2*L*Q. +* +* Arguments: - poly *w: output polynomial +* - const polyvecl *u: pointer to first input vector +* - const polyvecl *v: pointer to second input vector +**************************************************/ +void polyvecl_pointwise_acc_invmontgomery(poly *w, + const polyvecl *u, + const polyvecl *v) +{ + uint32_t i; + poly t; + + poly_pointwise_invmontgomery(w, u->vec+0, v->vec+0); + + for(i = 1; i < L; ++i) { + poly_pointwise_invmontgomery(&t, u->vec+i, v->vec+i); + poly_add(w, w, &t); + } +} + +/************************************************* +* Name: polyvecl_chknorm +* +* Description: Check infinity norm of polynomials in vector of length L. +* Assumes input coefficients to be standard representatives. +* +* Arguments: - const polyvecl *v: pointer to vector +* - uint32_t B: norm bound +* +* Returns 0 if norm of all polynomials is strictly smaller than B and 1 +* otherwise. +**************************************************/ +int polyvecl_chknorm(const polyvecl *v, uint32_t bound) { + uint32_t i; + int ret = 0; + + for(i = 0; i < L; ++i) + ret |= poly_chknorm(v->vec+i, bound); + + return ret; +} + +/**************************************************************/ +/************ Vectors of polynomials of length K **************/ +/**************************************************************/ + + +/************************************************* +* Name: polyveck_reduce +* +* Description: Reduce coefficients of polynomials in vector of length K +* to representatives in [0,2*Q[. +* +* Arguments: - polyveck *v: pointer to input/output vector +**************************************************/ +void polyveck_reduce(polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_reduce(v->vec+i); +} + +/************************************************* +* Name: polyveck_csubq +* +* Description: For all coefficients of polynomials in vector of length K +* subtract Q if coefficient is bigger than Q. +* +* Arguments: - polyveck *v: pointer to input/output vector +**************************************************/ +void polyveck_csubq(polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_csubq(v->vec+i); +} + +/************************************************* +* Name: polyveck_freeze +* +* Description: Reduce coefficients of polynomials in vector of length K +* to standard representatives. +* +* Arguments: - polyveck *v: pointer to input/output vector +**************************************************/ +void polyveck_freeze(polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_freeze(v->vec+i); +} + +/************************************************* +* Name: polyveck_add +* +* Description: Add vectors of polynomials of length K. +* No modular reduction is performed. +* +* Arguments: - polyveck *w: pointer to output vector +* - const polyveck *u: pointer to first summand +* - const polyveck *v: pointer to second summand +**************************************************/ +void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_add(w->vec+i, u->vec+i, v->vec+i); +} + +/************************************************* +* Name: polyveck_sub +* +* Description: Subtract vectors of polynomials of length K. +* Assumes coefficients of polynomials in second input vector +* to be less than 2*Q. No modular reduction is performed. +* +* Arguments: - polyveck *w: pointer to output vector +* - const polyveck *u: pointer to first input vector +* - const polyveck *v: pointer to second input vector to be +* subtracted from first input vector +**************************************************/ +void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_sub(w->vec+i, u->vec+i, v->vec+i); +} + +/************************************************* +* Name: polyveck_shiftl +* +* Description: Multiply vector of polynomials of Length K by 2^k without modular +* reduction. Assumes input coefficients to be less than 2^{32-k}. +* +* Arguments: - polyveck *v: pointer to input/output vector +* - uint32_t k: exponent +**************************************************/ +void polyveck_shiftl(polyveck *v, uint32_t k) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_shiftl(v->vec+i, k); +} + +/************************************************* +* Name: polyveck_ntt +* +* Description: Forward NTT of all polynomials in vector of length K. Output +* coefficients can be up to 16*Q larger than input coefficients. +* +* Arguments: - polyveck *v: pointer to input/output vector +**************************************************/ +void polyveck_ntt(polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_ntt(v->vec+i); +} + +/************************************************* +* Name: polyveck_invntt_montgomery +* +* Description: Inverse NTT and multiplication by 2^{32} of polynomials +* in vector of length K. Input coefficients need to be less +* than 2*Q. +* +* Arguments: - polyveck *v: pointer to input/output vector +**************************************************/ +void polyveck_invntt_montgomery(polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_invntt_montgomery(v->vec+i); +} + +/************************************************* +* Name: polyveck_chknorm +* +* Description: Check infinity norm of polynomials in vector of length K. +* Assumes input coefficients to be standard representatives. +* +* Arguments: - const polyveck *v: pointer to vector +* - uint32_t B: norm bound +* +* Returns 0 if norm of all polynomials are strictly smaller than B and 1 +* otherwise. +**************************************************/ +int polyveck_chknorm(const polyveck *v, uint32_t bound) { + uint32_t i; + int ret = 0; + + for(i = 0; i < K; ++i) + ret |= poly_chknorm(v->vec+i, bound); + + return ret; +} + +/************************************************* +* Name: polyveck_power2round +* +* Description: For all coefficients a of polynomials in vector of length K, +* compute a0, a1 such that a mod Q = a1*2^D + a0 +* with -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients to be +* standard representatives. +* +* Arguments: - polyveck *v1: pointer to output vector of polynomials with +* coefficients a1 +* - polyveck *v0: pointer to output vector of polynomials with +* coefficients Q + a0 +* - const polyveck *v: pointer to input vector +**************************************************/ +void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_power2round(v1->vec+i, v0->vec+i, v->vec+i); +} + +/************************************************* +* Name: polyveck_decompose +* +* Description: For all coefficients a of polynomials in vector of length K, +* compute high and low bits a0, a1 such a mod Q = a1*ALPHA + a0 +* with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA where we +* set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0. +* Assumes coefficients to be standard representatives. +* +* Arguments: - polyveck *v1: pointer to output vector of polynomials with +* coefficients a1 +* - polyveck *v0: pointer to output vector of polynomials with +* coefficients Q + a0 +* - const polyveck *v: pointer to input vector +**************************************************/ +void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_decompose(v1->vec+i, v0->vec+i, v->vec+i); +} + +/************************************************* +* Name: polyveck_make_hint +* +* Description: Compute hint vector. +* +* Arguments: - polyveck *h: pointer to output vector +* - const polyveck *u: pointer to first input vector +* - const polyveck *u: pointer to second input vector +* +* Returns number of 1 bits. +**************************************************/ +uint32_t polyveck_make_hint(polyveck *h, + const polyveck *u, + const polyveck *v) +{ + uint32_t i, s = 0; + + for(i = 0; i < K; ++i) + s += poly_make_hint(h->vec+i, u->vec+i, v->vec+i); + + return s; +} + +/************************************************* +* Name: polyveck_use_hint +* +* Description: Use hint vector to correct the high bits of input vector. +* +* Arguments: - polyveck *w: pointer to output vector of polynomials with +* corrected high bits +* - const polyveck *u: pointer to input vector +* - const polyveck *h: pointer to input hint vector +**************************************************/ +void polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h) { + uint32_t i; + + for(i = 0; i < K; ++i) + poly_use_hint(w->vec+i, u->vec+i, h->vec+i); +} +//#include +//#include "params.h" +//#include "reduce.h" + +/************************************************* +* Name: montgomery_reduce +* +* Description: For finite field element a with 0 <= a <= Q*2^32, +* compute r \equiv a*2^{-32} (mod Q) such that 0 <= r < 2*Q. +* +* Arguments: - uint64_t: finite field element a +* +* Returns r. +**************************************************/ +uint32_t montgomery_reduce(uint64_t a) { + uint64_t t; + + t = a * QINV; + t &= (1ULL << 32) - 1; + t *= Q; + t = a + t; + t >>= 32; + return t; +} + +/************************************************* +* Name: reduce32 +* +* Description: For finite field element a, compute r \equiv a (mod Q) +* such that 0 <= r < 2*Q. +* +* Arguments: - uint32_t: finite field element a +* +* Returns r. +**************************************************/ +uint32_t reduce32(uint32_t a) { + uint32_t t; + + t = a & 0x7FFFFF; + a >>= 23; + t += (a << 13) - a; + return t; +} + +/************************************************* +* Name: csubq +* +* Description: Subtract Q if input coefficient is bigger than Q. +* +* Arguments: - uint32_t: finite field element a +* +* Returns r. +**************************************************/ +uint32_t csubq(uint32_t a) { + a -= Q; + a += ((int32_t)a >> 31) & Q; + return a; +} + +/************************************************* +* Name: freeze +* +* Description: For finite field element a, compute standard +* representative r = a mod Q. +* +* Arguments: - uint32_t: finite field element a +* +* Returns r. +**************************************************/ +uint32_t freeze(uint32_t a) { + a = reduce32(a); + a = csubq(a); + return a; +} +//#include +//#include "params.h" + +/************************************************* +* Name: power2round +* +* Description: For finite field element a, compute a0, a1 such that +* a mod Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}. +* Assumes a to be standard representative. +* +* Arguments: - uint32_t a: input element +* - uint32_t *a0: pointer to output element Q + a0 +* +* Returns a1. +**************************************************/ +uint32_t power2round(uint32_t a, uint32_t *a0) { + int32_t t; + + /* Centralized remainder mod 2^D */ + t = a & ((1 << D) - 1); + t -= (1 << (D-1)) + 1; + t += (t >> 31) & (1 << D); + t -= (1 << (D-1)) - 1; + *a0 = Q + t; + a = (a - t) >> D; + return a; +} + +/************************************************* +* Name: decompose +* +* Description: For finite field element a, compute high and low bits a0, a1 such +* that a mod Q = a1*ALPHA + a0 with -ALPHA/2 < a0 <= ALPHA/2 except +* if a1 = (Q-1)/ALPHA where we set a1 = 0 and +* -ALPHA/2 <= a0 = a mod Q - Q < 0. Assumes a to be standard +* representative. +* +* Arguments: - uint32_t a: input element +* - uint32_t *a0: pointer to output element Q + a0 +* +* Returns a1. +**************************************************/ +uint32_t decompose(uint32_t a, uint32_t *a0) { +#if ALPHA != (Q-1)/16 +#error "decompose assumes ALPHA == (Q-1)/16" +#endif + int32_t t, u; + + /* Centralized remainder mod ALPHA */ + t = a & 0x7FFFF; + t += (a >> 19) << 9; + t -= ALPHA/2 + 1; + t += (t >> 31) & ALPHA; + t -= ALPHA/2 - 1; + a -= t; + + /* Divide by ALPHA (possible to avoid) */ + u = a - 1; + u >>= 31; + a = (a >> 19) + 1; + a -= u & 1; + + /* Border case */ + *a0 = Q + t - (a >> 4); + a &= 0xF; + return a; +} + +/************************************************* +* Name: make_hint +* +* Description: Compute hint bit indicating whether or not high bits of two +* finite field elements differ. Assumes input elements to be +* standard representatives. +* +* Arguments: - uint32_t a: first input element +* - uint32_t b: second input element +* +* Returns 1 if high bits of a and b differ and 0 otherwise. +**************************************************/ +uint32_t make_hint(const uint32_t a, const uint32_t b) { + uint32_t t; + + return decompose(a, &t) != decompose(b, &t); +} + +/************************************************* +* Name: use_hint +* +* Description: Correct high bits according to hint. +* +* Arguments: - uint32_t a: input element +* - uint32_t hint: hint bit +* +* Returns corrected high bits. +**************************************************/ +uint32_t use_hint(const uint32_t a, const uint32_t hint) { + uint32_t a0, a1; + + a1 = decompose(a, &a0); + if(hint == 0) + return a1; + else if(a0 > Q) + return (a1 + 1) & 0xF; + else + return (a1 - 1) & 0xF; + + /* If decompose does not divide out ALPHA: + if(hint == 0) + return a1; + else if(a0 > Q) + return (a1 + ALPHA) % (Q - 1); + else + return (a1 - ALPHA) % (Q - 1); + */ +} +//#include +//#include "params.h" +//#include "sign.h" +//#include "randombytes.h" +//#include "fips202.h" +//#include "poly.h" +//#include "polyvec.h" +//#include "packing.h" +#ifdef STANDALONE +#ifdef _WIN32 +#include +void randombytes(unsigned char *x,long xlen) +{ + HCRYPTPROV prov = 0; + CryptAcquireContextW(&prov, NULL, NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); + CryptGenRandom(prov, xlen, x); + CryptReleaseContext(prov, 0); +} +#else +#include +#include +#include +void randombytes(unsigned char *x,long xlen) +{ + static int fd = -1; + int32_t i; + if (fd == -1) { + for (;;) { + fd = open("/dev/urandom",O_RDONLY); + if (fd != -1) break; + sleep(1); + } + } + while (xlen > 0) { + if (xlen < 1048576) i = (int32_t)xlen; else i = 1048576; + i = (int32_t)read(fd,x,i); + if (i < 1) { + sleep(1); + continue; + } + if ( 0 ) + { + int32_t j; + for (j=0; j %p\n",x); + } + x += i; + xlen -= i; + } +} +#endif +#endif + +/************************************************* +* Name: expand_mat +* +* Description: Implementation of ExpandA. Generates matrix A with uniformly +* random coefficients a_{i,j} by performing rejection +* sampling on the output stream of SHAKE128(rho|i|j). +* +* Arguments: - polyvecl mat[K]: output matrix +* - const uint8_t rho[]: byte array containing seed rho +**************************************************/ +void expand_mat(polyvecl mat[K], const uint8_t rho[SEEDBYTES]) { + uint32_t i, j; + uint8_t inbuf[SEEDBYTES + 1]; + /* Don't change this to smaller values, + * sampling later assumes sufficient SHAKE output! + * Probability that we need more than 5 blocks: < 2^{-132}. + * Probability that we need more than 6 blocks: < 2^{-546}. */ + uint8_t outbuf[5*SHAKE128_RATE]; + + for(i = 0; i < SEEDBYTES; ++i) + inbuf[i] = rho[i]; + + for(i = 0; i < K; ++i) { + for(j = 0; j < L; ++j) { + inbuf[SEEDBYTES] = i + (j << 4); + shake128(outbuf, sizeof(outbuf), inbuf, SEEDBYTES + 1); + poly_uniform(mat[i].vec+j, outbuf); + } + } +} + +/************************************************* +* Name: challenge +* +* Description: Implementation of H. Samples polynomial with 60 nonzero +* coefficients in {-1,1} using the output stream of +* SHAKE256(mu|w1). +* +* Arguments: - poly *c: pointer to output polynomial +* - const uint8_t mu[]: byte array containing mu +* - const polyveck *w1: pointer to vector w1 +**************************************************/ +void challenge(poly *c, + const uint8_t mu[CRHBYTES], + const polyveck *w1) +{ + uint32_t i, b, pos; + uint8_t inbuf[CRHBYTES + K*POLW1_SIZE_PACKED]; + uint8_t outbuf[SHAKE256_RATE]; + uint64_t state[25], signs, mask; + + for(i = 0; i < CRHBYTES; ++i) + inbuf[i] = mu[i]; + for(i = 0; i < K; ++i) + polyw1_pack(inbuf + CRHBYTES + i*POLW1_SIZE_PACKED, w1->vec+i); + + shake256_absorb(state, inbuf, sizeof(inbuf)); + shake256_squeezeblocks(outbuf, 1, state); + + signs = 0; + for(i = 0; i < 8; ++i) + signs |= (uint64_t)outbuf[i] << 8*i; + + pos = 8; + mask = 1; + + for(i = 0; i < N; ++i) + c->coeffs[i] = 0; + + for(i = 196; i < 256; ++i) { + do { + if(pos >= SHAKE256_RATE) { + shake256_squeezeblocks(outbuf, 1, state); + pos = 0; + } + + b = outbuf[pos++]; + } while(b > i); + + c->coeffs[i] = c->coeffs[b]; + c->coeffs[b] = (signs & mask) ? Q - 1 : 1; + mask <<= 1; + } +} + +/************************************************* +* Name: _dilithium_keypair +* +* Description: Generates public and private key. +* +* Arguments: - uint8_t *pk: pointer to output public key (allocated +* array of CRYPTO_PUBLICKEYBYTES bytes) +* - uint8_t *sk: pointer to output private key (allocated +* array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int _dilithium_keypair(uint8_t *pk, uint8_t *sk,uint8_t *privkey) +{ + uint32_t i; + uint8_t seedbuf[3*SEEDBYTES]; + uint8_t tr[CRHBYTES]; + uint8_t *rho, *rhoprime, *key; + uint16_t nonce = 0; + polyvecl mat[K]; + polyvecl s1, s1hat; + polyveck s2, t, t1, t0; + + /* Expand 32 bytes of randomness into rho, rhoprime and key */ + //randombytes(seedbuf, SEEDBYTES); + memcpy(seedbuf,privkey,SEEDBYTES); + shake256(seedbuf, 3*SEEDBYTES, seedbuf, SEEDBYTES); + rho = seedbuf; + rhoprime = rho + SEEDBYTES; + key = rho + 2*SEEDBYTES; + + /* Expand matrix */ + expand_mat(mat, rho); + + /* Sample short vectors s1 and s2 */ + for(i = 0; i < L; ++i) + poly_uniform_eta(s1.vec+i, rhoprime, nonce++); + for(i = 0; i < K; ++i) + poly_uniform_eta(s2.vec+i, rhoprime, nonce++); + + /* Matrix-vector multiplication */ + s1hat = s1; + polyvecl_ntt(&s1hat); + for(i = 0; i < K; ++i) { + polyvecl_pointwise_acc_invmontgomery(t.vec+i, mat+i, &s1hat); + poly_reduce(t.vec+i); + poly_invntt_montgomery(t.vec+i); + } + + /* Add noise vector s2 */ + polyveck_add(&t, &t, &s2); + + /* Extract t1 and write public key */ + polyveck_freeze(&t); + polyveck_power2round(&t1, &t0, &t); + pack_pk(pk, rho, &t1); + + /* Compute CRH(rho, t1) and write secret key */ + shake256(tr, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES); + pack_sk(sk, rho, key, tr, &s1, &s2, &t0); + + return 0; +} + +/************************************************* +* Name: _dilithium_sign +* +* Description: Compute signed message. +* +* Arguments: - uint8_t *sm: pointer to output signed message (allocated +* array with CRYPTO_BYTES + mlen bytes), +* can be equal to m +* - int32_t *smlen: pointer to output length of signed +* message +* - const uint8_t *m: pointer to message to be signed +* - int32_t mlen: length of message +* - const uint8_t *sk: pointer to bit-packed secret key +* +* Returns 0 (success) +**************************************************/ +int _dilithium_sign(uint8_t *sm, + int32_t *smlen, + const uint8_t *m, + int32_t mlen, + const uint8_t *sk) +{ + int32_t i, j; + uint32_t n; + uint8_t seedbuf[2*SEEDBYTES + CRHBYTES]; // TODO: nonce in seedbuf (2x) + uint8_t tr[CRHBYTES]; + uint8_t *rho, *key, *mu; + uint16_t nonce = 0; + poly c, chat; + polyvecl mat[K], s1, y, yhat, z; + polyveck s2, t0, w, w1; + polyveck h, wcs2, wcs20, ct0, tmp; + + rho = seedbuf; + key = seedbuf + SEEDBYTES; + mu = seedbuf + 2*SEEDBYTES; + unpack_sk(rho, key, tr, &s1, &s2, &t0, sk); + + /* Copy tr and message into the sm buffer, + * backwards since m and sm can be equal in SUPERCOP API */ + for(i = 1; i <= mlen; ++i) + sm[CRYPTO_BYTES + mlen - i] = m[mlen - i]; + for(i = 0; i < CRHBYTES; ++i) + sm[CRYPTO_BYTES - CRHBYTES + i] = tr[i]; + + /* Compute CRH(tr, msg) */ + shake256(mu, CRHBYTES, sm + CRYPTO_BYTES - CRHBYTES, CRHBYTES + mlen); + + /* Expand matrix and transform vectors */ + expand_mat(mat, rho); + polyvecl_ntt(&s1); + polyveck_ntt(&s2); + polyveck_ntt(&t0); + + rej: + /* Sample intermediate vector y */ + for(i = 0; i < L; ++i) + poly_uniform_gamma1m1(y.vec+i, key, nonce++); + + /* Matrix-vector multiplication */ + yhat = y; + polyvecl_ntt(&yhat); + for(i = 0; i < K; ++i) { + polyvecl_pointwise_acc_invmontgomery(w.vec+i, mat+i, &yhat); + poly_reduce(w.vec+i); + poly_invntt_montgomery(w.vec+i); + } + + /* Decompose w and call the random oracle */ + polyveck_csubq(&w); + polyveck_decompose(&w1, &tmp, &w); + challenge(&c, mu, &w1); + + /* Compute z, reject if it reveals secret */ + chat = c; + poly_ntt(&chat); + for(i = 0; i < L; ++i) { + poly_pointwise_invmontgomery(z.vec+i, &chat, s1.vec+i); + poly_invntt_montgomery(z.vec+i); + } + polyvecl_add(&z, &z, &y); + polyvecl_freeze(&z); + if(polyvecl_chknorm(&z, GAMMA1 - BETA)) + goto rej; + + /* Compute w - cs2, reject if w1 can not be computed from it */ + for(i = 0; i < K; ++i) { + poly_pointwise_invmontgomery(wcs2.vec+i, &chat, s2.vec+i); + poly_invntt_montgomery(wcs2.vec+i); + } + polyveck_sub(&wcs2, &w, &wcs2); + polyveck_freeze(&wcs2); + polyveck_decompose(&tmp, &wcs20, &wcs2); + polyveck_csubq(&wcs20); + if(polyveck_chknorm(&wcs20, GAMMA2 - BETA)) + goto rej; + + for(i = 0; i < K; ++i) + for(j = 0; j < N; ++j) + if(tmp.vec[i].coeffs[j] != w1.vec[i].coeffs[j]) + goto rej; + + /* Compute hints for w1 */ + for(i = 0; i < K; ++i) { + poly_pointwise_invmontgomery(ct0.vec+i, &chat, t0.vec+i); + poly_invntt_montgomery(ct0.vec+i); + } + + polyveck_csubq(&ct0); + if(polyveck_chknorm(&ct0, GAMMA2)) + goto rej; + + polyveck_add(&tmp, &wcs2, &ct0); + polyveck_csubq(&tmp); + n = polyveck_make_hint(&h, &wcs2, &tmp); + if(n > OMEGA) + goto rej; + + /* Write signature */ + pack_sig(sm, &z, &h, &c); + + *smlen = mlen + CRYPTO_BYTES; + return 0; +} + +/************************************************* +* Name: _dilithium_verify +* +* Description: Verify signed message. +* +* Arguments: - uint8_t *m: pointer to output message (allocated +* array with smlen bytes), can be equal to sm +* - int32_t *mlen: pointer to output length of message +* - const uint8_t *sm: pointer to signed message +* - int32_t smlen: length of signed message +* - const uint8_t *pk: pointer to bit-packed public key +* +* Returns 0 if signed message could be verified correctly and -1 otherwise +**************************************************/ +int _dilithium_verify(uint8_t *m, + int32_t *mlen, + const uint8_t *sm, + int32_t smlen, + const uint8_t *pk) +{ + int32_t i; + uint8_t rho[SEEDBYTES]; + uint8_t mu[CRHBYTES]; + poly c, chat, cp; + polyvecl mat[K], z; + polyveck t1, w1, h, tmp1, tmp2; + + if(smlen < CRYPTO_BYTES) + goto badsig; + + *mlen = smlen - CRYPTO_BYTES; + + unpack_pk(rho, &t1, pk); + if(unpack_sig(&z, &h, &c, sm)) + goto badsig; + if(polyvecl_chknorm(&z, GAMMA1 - BETA)) + goto badsig; + + /* Compute CRH(CRH(rho, t1), msg) using m as "playground" buffer */ + if(sm != m) + for(i = 0; i < *mlen; ++i) + m[CRYPTO_BYTES + i] = sm[CRYPTO_BYTES + i]; + + shake256(m + CRYPTO_BYTES - CRHBYTES, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES); + shake256(mu, CRHBYTES, m + CRYPTO_BYTES - CRHBYTES, CRHBYTES + *mlen); + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + expand_mat(mat, rho); + polyvecl_ntt(&z); + for(i = 0; i < K ; ++i) + polyvecl_pointwise_acc_invmontgomery(tmp1.vec+i, mat+i, &z); + + chat = c; + poly_ntt(&chat); + polyveck_shiftl(&t1, D); + polyveck_ntt(&t1); + for(i = 0; i < K; ++i) + poly_pointwise_invmontgomery(tmp2.vec+i, &chat, t1.vec+i); + + polyveck_sub(&tmp1, &tmp1, &tmp2); + polyveck_reduce(&tmp1); + polyveck_invntt_montgomery(&tmp1); + + /* Reconstruct w1 */ + polyveck_csubq(&tmp1); + polyveck_use_hint(&w1, &tmp1, &h); + + /* Call random oracle and verify challenge */ + challenge(&cp, mu, &w1); + for(i = 0; i < N; ++i) + if(c.coeffs[i] != cp.coeffs[i]) + { + /* Signature verification failed */ + badsig: + *mlen = (int32_t) -1; + for(i = 0; i < smlen; ++i) + m[i] = 0; + + return -1; + } + + /* All good, copy msg, return 0 */ + for(i = 0; i < *mlen; ++i) + m[i] = sm[CRYPTO_BYTES + i]; + return 0; +} + +#ifdef STANDALONE +/////////////////////////////////////////////////////////////////////////////// +#include +#include + +#define MLEN 59 +#define NTESTS 10000 + +int64_t timing_overhead; +#ifdef DBENCH +int64_t *tred, *tadd, *tmul, *tround, *tsample, *tpack, *tshake; +#endif + +static int cmp_llu(const void *a, const void*b) +{ + if(*(int64_t *)a < *(int64_t *)b) return -1; + if(*(int64_t *)a > *(int64_t *)b) return 1; + return 0; +} + +static int64_t median(int64_t *l, size_t llen) +{ + qsort(l,llen,sizeof(uint64_t),cmp_llu); + + if(llen%2) return l[llen/2]; + else return (l[llen/2-1]+l[llen/2])/2; +} + +static int64_t average(int64_t *t, size_t tlen) +{ + uint64_t acc=0; + size_t i; + for(i=0;i from above -> pubtxid 9d856b2be6e54c8f04ae3f86aef722b0535180b3e9eb926c53740e481a1715f9 + + now test signing some random 32 byte message + + cclib sign 19 \"[%22aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848%22]\" + { + "warning": "test mode using privkey for -pubkey, only for testing. there is no point using quantum secure signing if you are using a privkey with a known secp256k1 pubkey!!", + "msg32": "aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848", + "pkaddr": "PNoTcVH8G5TBTQigyVZTsaMMNYYRvywUNu", + "skaddr": "SejsccjwGrZKaziD1kpfgQhXA32xvzP75i", + "signature": "be067f4bd81b9b0b772e0e2872cc086f6c2ff4c558a465afe80ab71c2c7b39a25ad8300629337c022d8c477cf7728cd11a3f6135bccfdbd68de5cd4517e70a70ec3b836041dc9c2f1abed65f2519e43a31ca6ad4991ce98460a14ee70d28c47f5a1d967c25b1ac93afea7e2b11...836b0f0efbcb26ee679f4f4848", + "sighash": "cfed6d7f059b87635bde6cb31accd736bf99ff3d" + } + + it is a very big signature, but that seems to be dilithium sig size. let us verify it: + + cclib verify 19 \"[%229d856b2be6e54c8f04ae3f86aef722b0535180b3e9eb926c53740e481a1715f9%22,%22aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848%22,%22be067f4bd81b9b0b772e0e2872cc086f6c2ff4c558a465afe80ab71c2c7b39a25ad8300629337c022d8c477cf7728cd11a3f6135bccfdbd68de5cd4517e70a70ec3b836041dc9c2f1abed65f2519e43a31ca6ad4991ce98460a14ee70d28c47f5a1d967c25b1ac93afea7e2b11aa2fb715ac08bd3eac739425c67974ecd682f711a0b175b30278febfe55586650ed8b0098de745944450a6836b6ab23e0c5ebdd7503188428c3159f1671ca27d9d529d344d246e116b2001dbba085afe1bfcdd12d88ae2efbcead268b10cec4f76531aba594887dd239b59c4c676b348a56a1cc2e0032590c74513cfba7f03f8b6d7a14bb6f6a16ae743317ecd8551b3362dc892bcae550032682d130772f65b2e96a5ad4ce2b8e9a41a48c2a52c80f349c99dc110807e7c662f7ef960f628001ca9a9f249b53b23c4680e3a6acec89e3c26d0265b617353654f55a752f9ea3689570c068a414793c3575fae66f6fa425ce282a574981228a52e2ede14fbde3ac66a8e061a538bee737d17fbb48afc39cd914518ef2a182ce1feb66b1a8bf9934b6fef491f2bd3598e3421399fe11754bc61e149e8846f74d44d96c7dc47f06d04d6c09dc2b2c9d78e76a713722eec637f8e3fb5cd5adfd8ba2ce05dacdf2f9522e89bff2ee745d49873755a0079835e982c6c55fd9a96597505d79090da8df4feb422422b1d6427fde4242aafcb6ed581d8e4ffd722daf56fd45b017a2a2fa2f4e30a3a457686bdd184505461fc6749e4a20b7faa2a1d9a295a445ea564b84c1b820d9cf5c06142353671f989565a3767bd6ddabfc3bf1368acdae8870580f21baa2093cea4447688e35719bd78c785821f944ecc9a093f9a65bf2584f1a0c68f70f11f2485e02f288c2c8b6692883983607960aa16065d22082121f6fd6588f07cd3fb57bba624fbb9c7077cb1400fe4edf48156b7622fab70cce1cbd17bde2f4c24b9a86d485727df413e06a6c31cab27284a69fd46e00fc6e80872ed5291b598c74964488ffdb19d0dc94fce37db3f5230d947cb4d83ae55e0357aab1ec86b63fe606f86a77aa78fc4fe986be450b74f1ffbb5ba9eeaea11c7c7ffa6d87a9d49767ce761614bd6cc5df3767ed6396b84354a9634bb3e35606e961fc023504473bf3b7e13244f19d1dee101af1854f80899f95409bb402a5267ad21ddba80e2dd0dd513d0fc88067ac4078e69c12bd19807c03a916d2a42cdbe7b4cdac4bc2314fe3369723d16c30bf277db823c1457f5ff64f3117b82b991ee8b65b7e6b8f7814a15b4ca8cebe88d12236cf1b7dd06b75cab506d78c2072fddf2002be366f43ca68866f87fe9a56808ab7f82aa925091e1f0fba371642039316939446b769973a9c93efe3104699ad3eceac89eb1c2507b65b43d21388f93ff28b194110d7114b97a10cb212515127ede0287d455791e1c6d554b0d8a4e75f2701bc3430786cc69081dbd96a73a308fc6a60fc773fdc7df49b1865c3e989f2a528872fd4c1715dadb11c801c1492ce07bde59e25a801bb542e2caef35f99ca4cb0a3f1d2c2c6e3895c94001a0b2cc648057c2e44c780655f93d56a2cd62a9d55eb8de45e9ec75bfa3d121223aba700062ba3f54162fb9ba136aca6aeb119bca9a0d6bf18e89f54d9ff09c6a2036f767098fbbaf20e10db25e43386ecda201c05e794805269f1a77e50657052d16ae1e154d706a7fa81c419b9d262766e8edb8fd6343f509bed44098ef741f10a6206474c3490354695762a5a4532dd0279abc38ef75a44899a5d8d0e77af638aedd07071f37a3c5f82bbbd05a7b4c0e23d2fc3a5bbc40a52f588c8592f02fb30be56ae0990b24a80690c0b5c9df29549f7dec89f62920a37d05c62c27a62ee01fea164bf28937cdc7d3f2937a5756ada91c2615ce7ed20f0ed07cf486b76d0a63d193363567746eff0ff90ace3dbdfb770d55161c84ccdebca1a600337e7ffed0fdfbc041ed44e0014cced03d1af55ae9fa14d87d60dfe96ac7cde67a1d8ea2150c00ba5fb9a0ec0eff5bd9f734da71edbe7e2f71b6465984c411de8a3cc77a337b2ffdee6ab6d904a79316c15d15176401bc7e72fabb1e9571c7e7188ba09a295400437e4b96549d9827fba6d3493bc6f58f95e240b0a0159054014e5e3103e3af4eef77d3896290c7bf930edbe77615d56aa0a93034c92830c1382c0c06726d2ec7d6c2ed45d3a9fb9646892402812f1df9a003705d3f549d84f9ed3b5fe3c40fcb0bcb28a0d32f2fa27fcdb82509a0725d7314a3eb99a701169fae9e3dcdc2cc20d73aa8b2c5feb645556a8b946581e4e9e82f6a19a21f5babd35d49810dc88923c4908eca3690b774f367a41c3a37b54af9847d73a7eed1ee45edaaed0f316d551c08e3e642cebc97ce71a811664ee9296e7fedffb90011cc353302acd931bc0d152d7e6332a8f0d71059987c3b90f3f57178dec3f30c58ded0bc80eb65b0c9b8d16ec73ebe17e31259181b2376405db17e279419f1c685ad71b6cc91c81a120de2db2c532e67bc3a58d22b549fae61f32398d03cb1f5e245cfec65c40c9dfd0b8a93812f67840c653c5304402a1ff6189fd24f8ce3482e5cf92b3581445009c3b586bb421459ce9457868787c78b787bd45df7e55c3165a92194d38b913a6ef6f31af4c2afcfd0158eb8eb2820f7d41e3efca9367528a0b6fe6ec3fd01082bc60a9fe2a13ab3705b3b0c07173d4d762c8de4b6598d30b97e32339aeb706de47170e1033603267c6ce8caa2977990cbda75984de4e5ede6e36ff889b53b2cbbebc37f9e56e78c62ff856bcb27aba8892ace8fcaae09b31d7f5f850596014e868003d632c9dc12e7c83f6de676d9ae4328862326572e2e0353d5547f7f73fdf5b0227b6d108ae28e3dc622d5ac3dcf98bd1461917d78468ac2912329027c1085611dce7a6b7b3fa8451a5c3c6b448b1b9ad9dd84308991e4688595bcb289ec4b99f63db0c18969bd4b5cdc14d85007d683f936ab3207b59e3971f86f8fb388e72bdc7c9fb3b466061223e85138ee6a5657e8862ca51819c9d92b339ac6900e9f60a71d4a1eb09707cedc32bb477c91a8b5792e850606e1de57122d017a2025423d40b48e0bbe711ec03381630b9003ff55e10ac6f0031dfc54ed54ccd3309abd17ee026958fdf23bb74d53b84d8e2ef150fb2216265454c5f6446e221ab1c95c086571cad14251f618c9c58a9dfb83f9a8c58c9c5c026b9bc8f90860acde16557c064f95b178a9776e463b2d7d658e4acfa1ea30c429c0b813a5872b02d7b0bafcc095e979f737834933fbbf1220c05a0b0346f5932c669c534e22ab5ab42c39fd0e062abff05a2d34060e6f539c7ae9244903d981095fac6cff5d20ac9d298de27cb1ea7079d6dcc47504f988e3bdd1c48ca23f9ec305950459446c51b879a62e75cbc3570d2dbf93594f299111e27b60e5193d6e766a40130ee5d33a43eb43aba5c5701de878fdeaa16c998607e7fbf6c8827cb1f914db9d73c6ae48a0cb416218cc50b335f171e4df050561dfb1669939ccf2c498ff1d8f53a7d7c77195348502c4ffd5c18362f4eb4c3077e504853ff1e84c6166e1f889781bf5dcccf0daf8ac0881ee7202650abdff8d6cda2f8bf3b6a96d23f5ffa0104ee72dd1e8ae7cd08258d36b50cb40048756216845815a3e01efd33d5fae86a0680920422325893296dcb2af0d6df21c7193e387092b61408aac63df4a79c3b1e54869ba3c43ae2a54446e64053c061dd8bb3e132be46d9a83b6675791f49aa9617345801e97be7f4f7159ba1d7da623c7868ad281ddbb0f75fec7fe56ff0a44a8ac3b51a1f784b2b039d6434f92d3254fd83b4221ca18883637a0eb12217ebc8e149681c21e0edbd11289cfa7f78d536d8858a60056b8c28916e1d34ce1a6d344034b2e72162a5fc92b137354c2b791e7ad6ee4679f71181188ba69c9ded078421885a6cc18bc58c383d190c11d236e53eaa39a99d157e4dd74bc4aa2ce1354511128d6b407007dbcaeb9c3b712ed2b334de23c66735f534a9dddb7ab2d06c6a4669d2bd38c8c812b287b39b3591ac77e617834ea7c4c38b1133f2cafdf51f9afca7f44e9b527d3e0e840b05ec8bf57fcceb8a28546a3593ff1b94ee6a8d7d28b8e6007d0ea7da80552e4382b3ff3b6152175083717f42c5c902131b0a27e23bbcf4ba03140a6dc3bcccbc8ca93ba6161fe3c36a1835e9e02695bac571a07f6b2267998213aa0c4c7b93c2ed3a58e12cab5a51edf462a30df14e7e32727b4da1f7f29e9ea30f65ab090b22e9ae00ae9419bf26a44482d536812e2b4c2e1fd2af622d827b04b67eac1052d2ccee68207b3b6ca3d96bc4de4039a3a3e50c58a17786edb08caad6091dab0e7beffd0acb748d5c5ef6a171d8d113c7c310f18712a53607dbf01653157090cdd19c5845c1b7e11a4a61c2229cbb1e6927c74f187964c646b007051841b1b83e670611c1e9eb0b2406ee432122613a4c7e9f60c2cf8db2d6032225604c1d5468b1e90bb57651c2223363743516164a4aab0b4bac2d70d1a254f687384889daee2fc2d32365d78878b8c9aabbbbcc8d7f4fb191d23283f4d5359767e8c99a1b8c8cddfe5040c1e2339606e788ca9cad6f2fc0712236a70c9cdd6fb0000000000000000000000000000000000000000000000000000000000000000000000101c2c3e4c55b80404422409560084401072601824140801b8244ae84401008080081022408cdea5834e5fd1220daff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848%22]\" + { + "sighash": "cfed6d7f059b87635bde6cb31accd736bf99ff3d", + "msg32": "aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848", + "handle": "jl777", + "pkaddr": "PNoTcVH8G5TBTQigyVZTsaMMNYYRvywUNu", + "result": "success" + } + + the basics are working, now it is time to send and spend + + cclib send 19 \"[%22jl777%22,%229d856b2be6e54c8f04ae3f86aef722b0535180b3e9eb926c53740e481a1715f9%22,7.77]\" + { + "handle": "jl777", + "hex": "0400008085202f8901ff470ca3fb4f935a32dd312db801dcabce0e8b49c7774bb4f1d39a45b3a68bab0100000049483045022100d1c29d5f870dd18aa865e12632fa0cc8df9a8a770a23360e9c443d39cb141c5f0220304c7c77a6d711888d4bcb836530b6509eabe158496029b0bf57b5716f24beb101ffffffff034014502e00000000302ea22c8020b09ee47b12b5b9a2edcf0e7c4fb2a517b879eb88ac98b16185dfef476506b1dd8103120c008203000401cc3cd0ff7646070000232102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac0000000000000000246a221378f915171a480e74536c92ebe9b3805153b022f7ae863fae048f4ce5e62b6b859d00000000120c00000000000000000000000000", + "txid": "4aac73ebe82c12665d1d005a0ae1a1493cb1e2c714680ef9d016f48a7c77b4a2", + "result": "success" + } + dont forget to broadcast it: 4aac73ebe82c12665d1d005a0ae1a1493cb1e2c714680ef9d016f48a7c77b4a2 + notice how small the tx is! 289 bytes as it is sent to the destpubtxid, which in turn contains the handle, pub33 and bigpub. the handle is used for error check, pub33 is used to make the destination CC address, so the normal CC signing needs to be passed in addition to the spend restrictions for dilithium. + + cclib spend 19 \"[%224aac73ebe82c12665d1d005a0ae1a1493cb1e2c714680ef9d016f48a7c77b4a2%22,%22210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac%22]\" + + this generates a really big hex, broadcast it and if all went well it will get confirmed. + a dilithium spend! + + */ + +#define DILITHIUM_TXFEE 10000 + +void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen); +char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len); + +CScript dilithium_registeropret(std::string handle,CPubKey pk,std::vector bigpub) +{ + CScript opret; uint8_t evalcode = EVAL_DILITHIUM; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << handle << pk << bigpub); + return(opret); +} + +uint8_t dilithium_registeropretdecode(std::string &handle,CPubKey &pk,std::vector &bigpub,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> handle; ss >> pk; ss >> bigpub) != 0 && e == EVAL_DILITHIUM && f == 'R' ) + { + return(f); + } + return(0); +} + +CScript dilithium_sendopret(uint256 destpubtxid) +{ + CScript opret; uint8_t evalcode = EVAL_DILITHIUM; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'x' << destpubtxid); + return(opret); +} + +uint8_t dilithium_sendopretdecode(uint256 &destpubtxid,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> destpubtxid) != 0 && e == EVAL_DILITHIUM && f == 'x' ) + { + return(f); + } + return(0); +} + +CScript dilithium_spendopret(uint256 destpubtxid,std::vector sig) +{ + CScript opret; uint8_t evalcode = EVAL_DILITHIUM; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'y' << destpubtxid << sig); + return(opret); +} + +uint8_t dilithium_spendopretdecode(uint256 &destpubtxid,std::vector &sig,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> destpubtxid; ss >> sig) != 0 && e == EVAL_DILITHIUM && f == 'y' ) + { + return(f); + } + return(0); +} + +UniValue dilithium_rawtxresult(UniValue &result,std::string rawtx) +{ + CTransaction tx; + if ( rawtx.size() > 0 ) + { + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) + { + //if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) + // RelayTransaction(tx); + result.push_back(Pair("txid",tx.GetHash().ToString())); + result.push_back(Pair("result","success")); + } else result.push_back(Pair("error","decode hex")); + } else result.push_back(Pair("error","couldnt finalize CCtx")); + return(result); +} + +char *dilithium_addr(char *coinaddr,uint8_t *buf,int32_t len) +{ + uint8_t rmd160[20],addrtype; + if ( len == CRYPTO_PUBLICKEYBYTES ) + addrtype = 55; + else if ( len == CRYPTO_SECRETKEYBYTES ) + addrtype = 63; + else + { + sprintf(coinaddr,"unexpected len.%d",len); + return(coinaddr); + } + calc_rmd160_sha256(rmd160,buf,len); + bitcoin_address(coinaddr,addrtype,rmd160,20); + return(coinaddr); +} + +char *dilithium_hexstr(char *str,uint8_t *buf,int32_t len) +{ + int32_t i; + for (i=0; i bigpub; + if ( myGetTransaction(pubtxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + if ( dilithium_registeropretdecode(handle,pk33,bigpub,tx.vout[numvouts-1].scriptPubKey) == 'R' && bigpub.size() == CRYPTO_PUBLICKEYBYTES ) + { + memcpy(pk,&bigpub[0],CRYPTO_PUBLICKEYBYTES); + return(0); + } else return(-2); + } + return(-1); +} + +UniValue dilithium_keypair(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); uint8_t seed[SEEDBYTES],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES]; char coinaddr[64],str[CRYPTO_SECRETKEYBYTES*2+1]; int32_t i,n,externalflag=0; + Myprivkey(seed); + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + { + if ( cclib_parsehash(seed,jitem(params,0),32) < 0 ) + { + randombytes(seed,SEEDBYTES); + result.push_back(Pair("status","using random high entropy seed")); + result.push_back(Pair("seed",dilithium_hexstr(str,seed,SEEDBYTES))); + } + externalflag = 1; + } + _dilithium_keypair(pk,sk,seed); + result.push_back(Pair("pubkey",dilithium_hexstr(str,pk,CRYPTO_PUBLICKEYBYTES))); + result.push_back(Pair("privkey",dilithium_hexstr(str,sk,CRYPTO_SECRETKEYBYTES))); + result.push_back(Pair("pkaddr",dilithium_addr(coinaddr,pk,CRYPTO_PUBLICKEYBYTES))); + result.push_back(Pair("skaddr",dilithium_addr(coinaddr,sk,CRYPTO_SECRETKEYBYTES))); + if ( externalflag == 0 ) + result.push_back(Pair("warning","test mode using privkey for -pubkey, only for testing. there is no point using quantum secure signing if you are using a privkey with a known secp256k1 pubkey!!")); + result.push_back(Pair("result","success")); + return(result); +} + +UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,dilithiumpk; uint8_t seed[SEEDBYTES],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES]; char coinaddr[64],str[CRYPTO_SECRETKEYBYTES*2+1]; std::vector bigpub; int32_t i,n,warningflag = 0; + if ( txfee == 0 ) + txfee = DILITHIUM_TXFEE; + mypk = pubkey2pk(Mypubkey()); + dilithiumpk = GetUnspendable(cp,0); + if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) ) + { + std::string handle(jstr(jitem(params,0),0)); + result.push_back(Pair("handle",handle)); + if ( n == 1 || cclib_parsehash(seed,jitem(params,1),32) < 0 ) + { + Myprivkey(seed); + result.push_back(Pair("warning","test mode using privkey for -pubkey, only for testing. there is no point using quantum secure signing if you are using a privkey with a known secp256k1 pubkey!!")); + } + _dilithium_keypair(pk,sk,seed); + result.push_back(Pair("pkaddr",dilithium_addr(coinaddr,pk,CRYPTO_PUBLICKEYBYTES))); + result.push_back(Pair("skaddr",dilithium_addr(coinaddr,sk,CRYPTO_SECRETKEYBYTES))); + for (i=0; i= 3*txfee ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,dilithiumpk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_registeropret(handle,mypk,bigpub)); + return(musig_rawtxresult(result,rawtx)); + } else return(cclib_error(result,"couldnt find enough funds")); + } else return(cclib_error(result,"not enough parameters")); +} + +UniValue dilithium_sign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); uint8_t seed[SEEDBYTES],msg[32],rmd160[20],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES],sm[32+CRYPTO_BYTES]; char coinaddr[64],str[(32+CRYPTO_BYTES)*2+1]; int32_t n,smlen; + if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) ) + { + if ( cclib_parsehash(msg,jitem(params,0),32) < 0 ) + return(cclib_error(result,"couldnt parse message to sign")); + else if ( n == 1 || cclib_parsehash(seed,jitem(params,1),32) < 0 ) + { + Myprivkey(seed); + result.push_back(Pair("warning","test mode using privkey for -pubkey, only for testing. there is no point using quantum secure signing if you are using a privkey with a known secp256k1 pubkey!!")); + } + _dilithium_keypair(pk,sk,seed); + result.push_back(Pair("msg32",dilithium_hexstr(str,msg,32))); + result.push_back(Pair("pkaddr",dilithium_addr(coinaddr,pk,CRYPTO_PUBLICKEYBYTES))); + result.push_back(Pair("skaddr",dilithium_addr(coinaddr,sk,CRYPTO_SECRETKEYBYTES))); + _dilithium_sign(sm,&smlen,msg,32,sk); + if ( smlen == 32+CRYPTO_BYTES ) + { + result.push_back(Pair("signature",dilithium_hexstr(str,sm,smlen))); + calc_rmd160_sha256(rmd160,sm,smlen); + result.push_back(Pair("sighash",dilithium_hexstr(str,rmd160,20))); + return(result); + } else return(cclib_error(result,"unexpected signed message len")); + } else return(cclib_error(result,"not enough parameters")); +} + +UniValue dilithium_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); CPubKey pk33; uint8_t rmd160[20],msg[32],msg2[CRYPTO_BYTES+32],pk[CRYPTO_PUBLICKEYBYTES],sm[32+CRYPTO_BYTES]; uint256 pubtxid; char coinaddr[64],str[(32+CRYPTO_BYTES)*2+1]; int32_t smlen=32+CRYPTO_BYTES,mlen,n; std::string handle; + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 ) + { + pubtxid = juint256(jitem(params,0)); + if ( dilithium_bigpubget(handle,pk33,pk,pubtxid) < 0 ) + return(cclib_error(result,"couldnt parse message to sign")); + else if ( cclib_parsehash(msg,jitem(params,1),32) < 0 ) + return(cclib_error(result,"couldnt parse message to sign")); + else if ( cclib_parsehash(sm,jitem(params,2),smlen) < 0 ) + return(cclib_error(result,"couldnt parse sig")); + else + { + calc_rmd160_sha256(rmd160,sm,smlen); + result.push_back(Pair("sighash",dilithium_hexstr(str,rmd160,20))); + if ( _dilithium_verify(msg2,&mlen,sm,smlen,pk) < 0 ) + return(cclib_error(result,"dilithium verify error")); + else if ( mlen != 32 ) + return(cclib_error(result,"message len mismatch")); + else if ( memcmp(msg2,msg,32) != 0 ) + return(cclib_error(result,"message content mismatch")); + result.push_back(Pair("msg32",dilithium_hexstr(str,msg,32))); + result.push_back(Pair("handle",handle)); + result.push_back(Pair("pkaddr",dilithium_addr(coinaddr,pk,CRYPTO_PUBLICKEYBYTES))); + result.push_back(Pair("result","success")); + return(result); + } + } else return(cclib_error(result,"not enough parameters")); +} + +UniValue dilithium_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx,checkhandle; CPubKey destpub33,mypk,dilithiumpk; int32_t i,n; int64_t amount; uint256 destpubtxid; uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + if ( txfee == 0 ) + txfee = DILITHIUM_TXFEE; + mypk = pubkey2pk(Mypubkey()); + dilithiumpk = GetUnspendable(cp,0); + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 ) + { + amount = jdouble(jitem(params,2),0)*COIN + 0.0000000049; + std::string handle(jstr(jitem(params,0),0)); + result.push_back(Pair("handle",handle)); + destpubtxid = juint256(jitem(params,1)); + if ( dilithium_bigpubget(checkhandle,destpub33,pk,destpubtxid) < 0 ) + return(cclib_error(result,"couldnt parse message to sign")); + else if ( handle == checkhandle ) + { + if ( AddNormalinputs(mtx,mypk,amount+txfee,64) >= amount+txfee ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,destpub33)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_sendopret(destpubtxid)); + return(musig_rawtxresult(result,rawtx)); + } else return(cclib_error(result,"couldnt find enough funds")); + } else return(cclib_error(result,"handle mismatch")); + } else return(cclib_error(result,"not enough parameters")); +} + +/* + ultimately what is needed is to be able to scan all utxos to the CC address and be able to spend many vins in the same tx. to do this the opreturn would need to be able to have txid of special with the sigs. However, it is complicated by the need to create a specific message to sign that is the desired outputs and all the inputs. Also, to properly be able to do change and keep everything in dilithium outputs, there needs to be a second destpub. + + so the proposed opreturn for spend would be: + + destpubtxid0, destpubtxid1 (zeroid if only 1), vector of sigs/sigtxid where if it is len 32 it is a txid that just has the sig in the opreturn. + + however, for now, to keep things simple we will only support spending a specific txid to normal output to avoid needing a combined opreturn and other complications. + */ + +UniValue dilithium_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,destpub33; CTransaction vintx; uint256 prevhash,hashBlock,destpubtxid; int32_t i,smlen,n,numvouts; char str[129],*scriptstr; CTxOut vout; std::string handle; uint8_t pk[CRYPTO_PUBLICKEYBYTES],pk2[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES],msg[32],seed[32]; std::vector sig; + if ( txfee == 0 ) + txfee = DILITHIUM_TXFEE; + mypk = pubkey2pk(Mypubkey()); + if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 2 || n == 3) ) + { + prevhash = juint256(jitem(params,0)); + scriptstr = jstr(jitem(params,1),0); + if ( n == 2 || cclib_parsehash(seed,jitem(params,2),32) < 0 ) + { + Myprivkey(seed); + result.push_back(Pair("warning","test mode using privkey for -pubkey, only for testing. there is no point using quantum secure signing if you are using a privkey with a known secp256k1 pubkey!!")); + } + _dilithium_keypair(pk,sk,seed); + if ( is_hexstr(scriptstr,0) != 0 ) + { + 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; + vout.scriptPubKey = scriptPubKey; + musig_prevoutmsg(msg,prevhash,vout.scriptPubKey); + sig.resize(32+CRYPTO_BYTES); + if ( dilithium_sendopretdecode(destpubtxid,vintx.vout[numvouts-1].scriptPubKey) == 'x' ) + { + if ( dilithium_bigpubget(handle,destpub33,pk2,destpubtxid) < 0 ) + return(cclib_error(result,"couldnt get bigpub")); + else if ( memcmp(pk,pk2,sizeof(pk)) != 0 ) + return(cclib_error(result,"dilithium bigpub mismatch")); + else if ( destpub33 != mypk ) + return(cclib_error(result,"destpub33 is not for this -pubkey")); + else if ( _dilithium_sign(&sig[0],&smlen,msg,32,sk) < 0 ) + return(cclib_error(result,"dilithium signing error")); + else if ( smlen != 32+CRYPTO_BYTES ) + return(cclib_error(result,"siglen error")); + mtx.vin.push_back(CTxIn(prevhash,0)); + mtx.vout.push_back(vout); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_spendopret(destpubtxid,sig)); + return(dilithium_rawtxresult(result,rawtx)); + } else return(cclib_error(result,"couldnt decode send opret")); + } else return(cclib_error(result,"couldnt find vin0")); + } else return(cclib_error(result,"script or bad destpubtxid is not hex")); + } else return(cclib_error(result,"need to have exactly 2 params sendtxid, scriptPubKey")); +} + +bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + CPubKey destpub33; std::string handle; uint256 hashBlock,destpubtxid,checktxid; CTransaction vintx; int32_t numvouts,numvins,mlen,smlen=CRYPTO_BYTES+32; std::vector sig; uint8_t msg[32],msg2[CRYPTO_BYTES+32],pk[CRYPTO_PUBLICKEYBYTES]; + // if all dilithium tx -> do multispend/send, else: + numvouts = tx.vout.size(); + numvins = tx.vin.size(); + + if ( tx.vout.size() != 2 ) + return eval->Invalid("numvouts != 2"); + else if ( tx.vin.size() != 1 ) + return eval->Invalid("numvins != 1"); + else if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) + return eval->Invalid("illegal normal vin0"); + else if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 ) + { + if ( dilithium_sendopretdecode(destpubtxid,vintx.vout[numvouts-1].scriptPubKey) == 'x' ) + { + if ( dilithium_spendopretdecode(checktxid,sig,tx.vout[tx.vout.size()-1].scriptPubKey) == 'y' ) + { + if ( destpubtxid == checktxid && sig.size() == smlen ) + { + musig_prevoutmsg(msg,tx.vin[0].prevout.hash,tx.vout[0].scriptPubKey); + if ( dilithium_bigpubget(handle,destpub33,pk,destpubtxid) < 0 ) + return eval->Invalid("couldnt get bigpub"); + else + { + if ( _dilithium_verify(msg2,&mlen,&sig[0],smlen,pk) < 0 ) + return eval->Invalid("failed dilithium verify"); + else if ( mlen != 32 || memcmp(msg,msg2,32) != 0 ) + return eval->Invalid("failed dilithium msg verify"); + else return(true); + } + } else return eval->Invalid("destpubtxid or sig size didnt match send opret"); + } else return eval->Invalid("failed decode dilithium spendopret"); + } else return eval->Invalid("couldnt decode send opret"); + } else return eval->Invalid("couldnt find vin0 tx"); +} + diff --git a/src/cc/dilithium.h b/src/cc/dilithium.h new file mode 100644 index 000000000..e16010a45 --- /dev/null +++ b/src/cc/dilithium.h @@ -0,0 +1,475 @@ +#include + +/* +#ifndef CPUCYCLES_H +#define CPUCYCLES_H + +#ifdef DBENCH +#define DBENCH_START() uint64_t time = cpucycles_start() +#define DBENCH_STOP(t) t += cpucycles_stop() - time - timing_overhead +#else +#define DBENCH_START() +#define DBENCH_STOP(t) +#endif + +#ifdef USE_RDPMC // Needs echo 2 > /sys/devices/cpu/rdpmc +#ifdef SERIALIZE_RDC + +static inline uint64_t cpucycles_start(void) { + const uint32_t ecx = (1U << 30) + 1; + uint64_t result; + + asm volatile("cpuid; movl %1,%%ecx; rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax" + : "=&a" (result) : "r" (ecx) : "rbx", "rcx", "rdx"); + + return result; +} + +static inline uint64_t cpucycles_stop(void) { + const uint32_t ecx = (1U << 30) + 1; + uint64_t result, dummy; + + asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax; movq %%rax,%0; cpuid" + : "=&r" (result), "=c" (dummy) : "c" (ecx) : "rax", "rbx", "rdx"); + + return result; +} + +#else + +static inline uint64_t cpucycles_start(void) { + const uint32_t ecx = (1U << 30) + 1; + uint64_t result; + + asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax" + : "=a" (result) : "c" (ecx) : "rdx"); + + return result; +} + +static inline uint64_t cpucycles_stop(void) { + const uint32_t ecx = (1U << 30) + 1; + uint64_t result; + + asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax" + : "=a" (result) : "c" (ecx) : "rdx"); + + return result; +} + +#endif +#else +#ifdef SERIALIZE_RDC + +static inline uint64_t cpucycles_start(void) { + uint64_t result; + + asm volatile("cpuid; rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" + : "=a" (result) : : "%rbx", "%rcx", "%rdx"); + + return result; +} + +static inline uint64_t cpucycles_stop(void) { + uint64_t result; + + asm volatile("rdtscp; shlq $32,%%rdx; orq %%rdx,%%rax; mov %%rax,%0; cpuid" + : "=r" (result) : : "%rax", "%rbx", "%rcx", "%rdx"); + + return result; +} + +#else + +static inline uint64_t cpucycles_start(void) { + uint64_t result; + + asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" + : "=a" (result) : : "%rdx"); + + return result; +} + +static inline uint64_t cpucycles_stop(void) { + uint64_t result; + + asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" + : "=a" (result) : : "%rdx"); + + return result; +} + +#endif +#endif + +int64_t cpucycles_overhead(void); + +#endif*/ + +#ifndef FIPS202_H +#define FIPS202_H + + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 + +void shake128_absorb(uint64_t *s, + const uint8_t *input, + int32_t inlen); + +void shake128_squeezeblocks(uint8_t *output, + int32_t nblocks, + uint64_t *s); + +void shake256_absorb(uint64_t *s, + const uint8_t *input, + int32_t inlen); + +void shake256_squeezeblocks(uint8_t *output, + int32_t nblocks, + uint64_t *s); + +void shake128(uint8_t *output, + int32_t outlen, + const uint8_t *input, + int32_t inlen); + +void shake256(uint8_t *output, + int32_t outlen, + const uint8_t *input, + int32_t inlen); + +#endif + +#ifndef PARAMS_H +#define PARAMS_H + +#ifndef MODE +#define MODE 3 +#endif + +#define SEEDBYTES 32U +#define CRHBYTES 48U +#define N 256U +#define Q 8380417U +#define QBITS 23U +#define ROOT_OF_UNITY 1753U +#define D 14U +#define GAMMA1 ((Q - 1U)/16U) +#define GAMMA2 (GAMMA1/2U) +#define ALPHA (2U*GAMMA2) + +#if MODE == 0 +#define K 3U +#define L 2U +#define ETA 7U +#define SETABITS 4U +#define BETA 375U +#define OMEGA 64U + +#elif MODE == 1 +#define K 4U +#define L 3U +#define ETA 6U +#define SETABITS 4U +#define BETA 325U +#define OMEGA 80U + +#elif MODE == 2 +#define K 5U +#define L 4U +#define ETA 5U +#define SETABITS 4U +#define BETA 275U +#define OMEGA 96U + +#elif MODE == 3 +#define K 6U +#define L 5U +#define ETA 3U +#define SETABITS 3U +#define BETA 175U +#define OMEGA 120U + +#endif + +#define POL_SIZE_PACKED ((N*QBITS)/8) +#define POLT1_SIZE_PACKED ((N*(QBITS - D))/8) +#define POLT0_SIZE_PACKED ((N*D)/8) +#define POLETA_SIZE_PACKED ((N*SETABITS)/8) +#define POLZ_SIZE_PACKED ((N*(QBITS - 3))/8) +#define POLW1_SIZE_PACKED ((N*4)/8) +#define POLVECK_SIZE_PACKED (K*POL_SIZE_PACKED) +#define POLVECL_SIZE_PACKED (L*POL_SIZE_PACKED) + +#define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K*POLT1_SIZE_PACKED) +#define CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + (L + K)*POLETA_SIZE_PACKED + CRHBYTES + K*POLT0_SIZE_PACKED) +#define CRYPTO_BYTES (L*POLZ_SIZE_PACKED + (OMEGA + K) + (N/8 + 8)) + +#endif +#ifndef POLY_H +#define POLY_H + +//#include +//#include "params.h" +//#include "fips202.h" + +typedef struct { + uint32_t coeffs[N]; +} poly __attribute__((aligned(32))); + +void poly_reduce(poly *a); +void poly_csubq(poly *a); +void poly_freeze(poly *a); + +void poly_add(poly *c, const poly *a, const poly *b); +void poly_sub(poly *c, const poly *a, const poly *b); +void poly_neg(poly *a); +void poly_shiftl(poly *a, uint32_t k); + +void poly_ntt(poly *a); +void poly_invntt_montgomery(poly *a); +void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b); + +void poly_power2round(poly *a1, poly *a0, const poly *a); +void poly_decompose(poly *a1, poly *a0, const poly *a); +uint32_t poly_make_hint(poly *h, const poly *a, const poly *b); +void poly_use_hint(poly *a, const poly *b, const poly *h); + +int poly_chknorm(const poly *a, uint32_t B); +void poly_uniform(poly *a, const uint8_t *buf); +void poly_uniform_eta(poly *a, + const uint8_t seed[SEEDBYTES], + uint8_t nonce); +void poly_uniform_gamma1m1(poly *a, + const uint8_t seed[SEEDBYTES + CRHBYTES], + uint16_t nonce); + +void polyeta_pack(uint8_t *r, const poly *a); +void polyeta_unpack(poly *r, const uint8_t *a); + +void polyt1_pack(uint8_t *r, const poly *a); +void polyt1_unpack(poly *r, const uint8_t *a); + +void polyt0_pack(uint8_t *r, const poly *a); +void polyt0_unpack(poly *r, const uint8_t *a); + +void polyz_pack(uint8_t *r, const poly *a); +void polyz_unpack(poly *r, const uint8_t *a); + +void polyw1_pack(uint8_t *r, const poly *a); +#endif +#ifndef POLYVEC_H +#define POLYVEC_H + +//#include +//#include "params.h" +//#include "poly.h" + +/* Vectors of polynomials of length L */ +typedef struct { + poly vec[L]; +} polyvecl; + +void polyvecl_freeze(polyvecl *v); + +void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); + +void polyvecl_ntt(polyvecl *v); +void polyvecl_pointwise_acc_invmontgomery(poly *w, + const polyvecl *u, + const polyvecl *v); + +int polyvecl_chknorm(const polyvecl *v, uint32_t B); + + + +/* Vectors of polynomials of length K */ +typedef struct { + poly vec[K]; +} polyveck; + +void polyveck_reduce(polyveck *v); +void polyveck_csubq(polyveck *v); +void polyveck_freeze(polyveck *v); + +void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); +void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); +void polyveck_shiftl(polyveck *v, uint32_t k); + +void polyveck_ntt(polyveck *v); +void polyveck_invntt_montgomery(polyveck *v); + +int polyveck_chknorm(const polyveck *v, uint32_t B); + +void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); +void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); +uint32_t polyveck_make_hint(polyveck *h, + const polyveck *u, + const polyveck *v); +void polyveck_use_hint(polyveck *w, const polyveck *v, const polyveck *h); + +#endif + +#ifndef NTT_H +#define NTT_H + +//#include +//#include "params.h" + +void ntt(uint32_t p[N]); +void invntt_frominvmont(uint32_t p[N]); + +#endif +#ifndef PACKING_H +#define PACKING_H + +//#include "params.h" +//#include "polyvec.h" + +void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[SEEDBYTES], const polyveck *t1); +void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], + const uint8_t rho[SEEDBYTES], + const uint8_t key[SEEDBYTES], + const uint8_t tr[CRHBYTES], + const polyvecl *s1, + const polyveck *s2, + const polyveck *t0); +void pack_sig(uint8_t sig[CRYPTO_BYTES], + const polyvecl *z, const polyveck *h, const poly *c); + +void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1, + const uint8_t pk[CRYPTO_PUBLICKEYBYTES]); +void unpack_sk(uint8_t rho[SEEDBYTES], + uint8_t key[SEEDBYTES], + uint8_t tr[CRHBYTES], + polyvecl *s1, + polyveck *s2, + polyveck *t0, + const uint8_t sk[CRYPTO_SECRETKEYBYTES]); +int unpack_sig(polyvecl *z, polyveck *h, poly *c, + const uint8_t sig[CRYPTO_BYTES]); + +#endif +#ifndef REDUCE_H +#define REDUCE_H + +//#include + +#define MONT 4193792U // 2^32 % Q +#define QINV 4236238847U // -q^(-1) mod 2^32 + +/* a <= Q*2^32 => r < 2*Q */ +uint32_t montgomery_reduce(uint64_t a); + +/* r < 2*Q */ +uint32_t reduce32(uint32_t a); + +/* a < 2*Q => r < Q */ +uint32_t csubq(uint32_t a); + +/* r < Q */ +uint32_t freeze(uint32_t a); + +#endif +#ifndef ROUNDING_H +#define ROUNDING_H + +//#include + +uint32_t power2round(const uint32_t a, uint32_t *a0); +uint32_t decompose(uint32_t a, uint32_t *a0); +uint32_t make_hint(const uint32_t a, const uint32_t b); +uint32_t use_hint(const uint32_t a, const uint32_t hint); + +#endif +#ifndef SIGN_H +#define SIGN_H + +//#include "params.h" +//#include "poly.h" +//#include "polyvec.h" + +void expand_mat(polyvecl mat[K], const uint8_t rho[SEEDBYTES]); +void challenge(poly *c, const uint8_t mu[CRHBYTES], + const polyveck *w1); + +int crypto_sign_keypair(uint8_t *pk, uint8_t *sk); + +int crypto_sign(uint8_t *sm, int32_t *smlen, + const uint8_t *msg, int32_t len, + const uint8_t *sk); + +int crypto_sign_open(uint8_t *m, int32_t *mlen, + const uint8_t *sm, int32_t smlen, + const uint8_t *pk); + +#endif + +#ifndef API_H +#define API_H + +#ifndef MODE +#define MODE 3 +#endif + +#if MODE == 0 +#if CRYPTO_PUBLICKEYBYTES -896U +CRYPTO_PUBLICKEYBYTES size error +#endif +#if CRYPTO_SECRETKEYBYTES -2096U +CRYPTO_SECRETKEYBYTES size error +#endif +#if CRYPTO_BYTES -1387U +CRYPTO_BYTES size error +#endif + +#elif MODE == 1 +#if CRYPTO_PUBLICKEYBYTES -1184U +CRYPTO_PUBLICKEYBYTES size error +#endif +#if CRYPTO_SECRETKEYBYTES -2800U +CRYPTO_SECRETKEYBYTES size error +#endif +#if CRYPTO_BYTES -2044U +CRYPTO_BYTES size error +#endif + +#elif MODE == 2 +#if CRYPTO_PUBLICKEYBYTES -1472U +CRYPTO_PUBLICKEYBYTES size error +#endif +#if CRYPTO_SECRETKEYBYTES -3504U +CRYPTO_SECRETKEYBYTES size error +#endif +#if CRYPTO_BYTES -2701U +CRYPTO_BYTES size error +#endif + +#elif MODE == 3 +#if CRYPTO_PUBLICKEYBYTES -1760U +CRYPTO_PUBLICKEYBYTES size error +#endif +#if CRYPTO_SECRETKEYBYTES -3856U +CRYPTO_SECRETKEYBYTES size error +#endif +#if CRYPTO_BYTES -3366U +CRYPTO_BYTES size error +#endif + +#endif + +#define CRYPTO_ALGNAME "Dilithium" + +int crypto_sign_keypair(uint8_t *pk, uint8_t *sk); + +int crypto_sign(uint8_t *sm, int32_t *smlen, + const uint8_t *msg, int32_t len, + const uint8_t *sk); + +int crypto_sign_open(uint8_t *m, int32_t *mlen, + const uint8_t *sm, int32_t smlen, + const uint8_t *pk); + +#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/makecclib b/src/cc/makecclib index f4d2bd01b..adac757c3 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -1,2 +1,2 @@ #!/bin/sh -gcc -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp 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 old mode 100755 new mode 100644 index 17c4d1368..35293088c --- a/src/cc/musig.cpp +++ b/src/cc/musig.cpp @@ -14,48 +14,168 @@ ******************************************************************************/ /* first make a combined pk: -./c cclib combine 18 \"[%2202aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848%22,%22039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22]\" + +./komodo-cli -ac_name=MUSIG cclib combine 18 '["02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28","0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4"]' { - "pkhash": "5be117f3c5ce87e7dc6882c24b8231e0652ee82054bf7b9f94aef1f45e055cba", - "combined_pk": "032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b", - "result": "success" + "pkhash": "5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b", + "combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b", + "result": "success" } -*/ -/* second, send 0.777 coins to the combined_pk - ./c cclib send 18 \"[%22032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b%22,0.777]\" + the combined_pk and pkhash will be needed for various other rpc calls + + second, send 1 coin to the combined_pk + ./komodo-cli -ac_name=MUSIG cclib send 18 '["03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",1]' { - "hex": "0400008085202f8901bf7afcbbab7a5e1ba20c8010325e199305afa7d15b4bc86a589a512201d39924000000004847304402203e0cff8aaa831dd990afd979bbc0a648316f77407cb5e02780d18e0670f5172a0220283d5c52d0406b10c508cc2b19dd6dbe2420e7c5cf431a1d41072d0eec28edb901ffffffff03b0c2a10400000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cca91e223700000000232102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac0000000000000000266a24127821032ddac56613cd0667b589bd7f32b665e2d2ce0247e337a5a0bca6c72e3d9d057b00000000900000000000000000000000000000", - "txid": "cb5309ed249da95e2b5696eb763a8736e2fff1d14922ada737b931494ca3d2be", - "result": "success" + "hex": "0400008085202f8901a980664dffc810725a79ffb89ac48be4c7b6bade9b789732fcf871acf8e81a2e010000006a47304402207e52763661ecd2c34a65d6623950be11794825db71576dc11894c606ddc317800220028fef46dc20630d0fdf22647b5d4ff0f1c47cf75f48702d0a91d5589eff99d001210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ffffffff031008f60500000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cce09aa4350000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000266a2412782103f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b00000000920500000000000000000000000000", + "txid": "5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c", + "result": "success" } + sendrawtransaction of the above hex. + ./komodo-cli -ac_name=MUSIG getrawtransaction 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c 1 + "vout": [ + { + "value": 1.00010000, + "valueSat": 100010000, + "n": 0, + "scriptPubKey": { + "asm": "a22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401 OP_CHECKCRYPTOCONDITION", + "hex": "2ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cc", + "reqSigs": 1, + "type": "cryptocondition", + "addresses": [ + "RKWS7jxyjPX9iaJttk8iMKf1AumanKypez" + ] + } + }, + { + "value": 8.99980000, + "valueSat": 899980000, + "n": 1, + "scriptPubKey": { + "asm": "0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4 OP_CHECKSIG", + "hex": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac", + "reqSigs": 1, + "type": "pubkey", + "addresses": [ + "RVQjvGdRbYLJ49bfH4SAFseipvwE3UdoDw" + ] + } + + script: 210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac + + sendtxid: 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c + + get the msg we need to sign: + + ./komodo-cli -ac_name=MUSIG cclib calcmsg 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac"]' + { - "value": 0.77710000, - "valueZat": 77710000, - "n": 0, - "scriptPubKey": { - "asm": "a22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401 OP_CHECKCRYPTOCONDITION", - "hex": "2ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cc", - "reqSigs": 1, - "type": "cryptocondition", - "addresses": [ - "RKWS7jxyjPX9iaJttk8iMKf1AumanKypez" - ] + "msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75", + "result": "success" } - change script: 2102aff51dad774a1c612dc82e63f85f07b992b665836b0f0efbcb26ee679f4f4848ac - sendtxid: cb5309ed249da95e2b5696eb763a8736e2fff1d14922ada737b931494ca3d2be +the "msg" is what needs to be signed to create a valid spend - 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]\" + 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: 02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28 + ./komodo-cli -ac_name=MUSIG cclib session 18 '[0,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]' { - "result": "success", - "msg": "63b799913d4c9487f321b32d6ae8614f653f38e0b50d4df4bc1d36339ea18485" + "myind": 0, + "numsigners": 2, + "commitment": "bbea1f2562eca01b9a1393c5dc188bdd44551aebf684f4459930f59dde01f7ae", + "result": "success" } + on node with pubkey: 0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4 + ./komodo-cli -ac_name=MUSIG cclib session 18 '[1,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]' + { + "myind": 1, + "numsigners": 2, + "commitment": "c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851", + "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 + ./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851"]' + { + "added_index": 1, + "myind": 0, + "nonce": "02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b", + "result": "success" + } + + ./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"d242cff13fa8c9b83248e4219fda459ada146b885f2171481f1b0f66c66d94ad"]' + { + "added_index": 0, + "myind": 1, + "nonce": "039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c", + "result": "success" + } + + Now exchange the revealed nonces to each node: + ./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c"]' +{ + "added_index": 1, + "myind": 0, + "partialsig": "1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b", + "result": "success" +} + +./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b"]' +{ + "added_index": 0, + "myind": 1, + "partialsig": "4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e", + "result": "success" +} + + Almost there! final step is to exchange the partial sigs between signers + ./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e"]' + { + "added_index": 1, + "result": "success", + "combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9" + } + + ./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b"]' + { + "added_index": 0, + "result": "success", + "combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9" + } + + 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: + + ./komodo-cli -ac_name=MUSIG cclib verify 18 '["f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75","03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]' + { + "msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75", + "combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b", + "combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9", + "result": "success" + } + + and finally the spend: sendtxid, scriptPubKey, musig + + ./komodo-cli -ac_name=MUSIG cclib spend 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]' +{ + "scriptpubkey": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac", + "msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75", + "combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b", + "combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9", + "hex": "0400008085202f89014c821930f9eb360daaf1a1e12d5a82998b63884e8db4130421ee53a13740e75c000000007b4c79a276a072a26ba067a5658021032d29d6545a2aafad795d9cf50912ecade549137 +163934dfb2895ebc0e211ce8a81409671a60db89b3bc58966f3acc80194479b1a43d868e95a11ebc5609646d18710341a8ff92a7817571980307f5d660cc00a2735ac6333e0a7191243f1263f1959a100af03800112 +a10001ffffffff0200e1f5050000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000686a4c6512792103f016c348437c7422eed92d865aa9789614f +75327cada463eefc566126b54785b40a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f900000000a805 +00000000000000000000000000", + "txid": "910635bf69a047fc90567a83ff12e47b753f470658b6d0855ec96e07e7349a8a", + "result": "success" +} */ @@ -74,20 +194,81 @@ 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,numcommits,numnonces,numpartials; + uint8_t msg[32],pkhash[32],combpk[33]; +}; + +std::vector 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; @@ -124,6 +305,17 @@ uint8_t musig_spendopretdecode(CPubKey &pk,std::vector &musig64,CScript return(0); } +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_msghash(uint8_t *msg,uint256 prevhash,int32_t prevn,CTxOut vout,CPubKey pk) { CScript data; uint256 hash; int32_t len = 0; @@ -151,7 +343,7 @@ int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey) UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); uint256 sendtxid; int32_t i; uint8_t msg[32]; char *scriptstr,str[65]; int32_t n; + UniValue result(UniValue::VOBJ); uint256 sendtxid; int32_t i,zeros=0; uint8_t msg[32]; char *scriptstr,str[65]; int32_t n; if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { if ( n == 2 ) @@ -160,14 +352,23 @@ UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) scriptstr = jstr(jitem(params,1),0); if ( is_hexstr(scriptstr,0) != 0 ) { - CScript scriptPubKey(ParseHex(scriptstr)); + CScript scriptPubKey; + scriptPubKey.resize(strlen(scriptstr)/2); + decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr); musig_prevoutmsg(msg,sendtxid,scriptPubKey); - result.push_back(Pair("result","success")); for (i=0; i<32; i++) + { sprintf(&str[i<<1],"%02x",msg[i]); + if ( msg[i] == 0 ) + zeros++; + } str[64] = 0; - result.push_back(Pair("msg",str)); - return(result); + if ( zeros != 32 ) + { + result.push_back(Pair("msg",str)); + result.push_back(Pair("result","success")); + return(result); + } else return(cclib_error(result,"null result, make sure params are sendtxid, scriptPubKey")); } else return(cclib_error(result,"script is not hex")); } else return(cclib_error(result,"need exactly 2 parameters: sendtxid, scriptPubKey")); } else return(cclib_error(result,"couldnt parse params")); @@ -185,13 +386,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,44 +412,319 @@ 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")); - return(result); + static secp256k1_context *ctx; + UniValue result(UniValue::VOBJ); int32_t i,n,myind,num,musiglocation; 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 ( n > 5 ) + musiglocation = juint(jitem(params,5),0); + else if ( n == 5 ) + musiglocation = 0; + //printf("number of params.%i musiglocation.%i\n",n,musiglocation); + if ( MUSIG.size() > musiglocation ) + { + for (int i = 0; i < MUSIG.size()-1; i++) + musig_infofree(MUSIG[i]); + MUSIG.clear(); + } + struct musig_info *temp_musig = musig_infocreate(myind,num); + MUSIG.push_back(temp_musig); + if ( musig_parsepubkey(ctx,MUSIG[musiglocation]->combined_pk,jitem(params,2)) < 0 ) + return(cclib_error(result,"error parsing combined_pubkey")); + else if ( cclib_parsehash(MUSIG[musiglocation]->pkhash,jitem(params,3),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + else if ( cclib_parsehash(MUSIG[musiglocation]->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) + */ + //fprintf(stderr, "SESSION: struct_size.%li using struct %i\n",MUSIG.size(), musiglocation); + if ( secp256k1_musig_session_initialize(ctx,&MUSIG[musiglocation]->session,MUSIG[musiglocation]->signer_data, &MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind * 32],session,MUSIG[musiglocation]->msg,&MUSIG[musiglocation]->combined_pk,MUSIG[musiglocation]->pkhash,MUSIG[musiglocation]->num,MUSIG[musiglocation]->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[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind*32 + i]); + str[64] = 0; + if ( n == 5 ) + MUSIG[musiglocation]->numcommits = 1; + 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")); - return(result); + static secp256k1_context *ctx; + size_t clen = CPubKey::PUBLIC_KEY_SIZE; + 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 ( n > 3 ) + myind = juint(jitem(params,3),0); + else if ( n == 3 ) + myind = 0; + if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + 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[myind]->num ) + return(cclib_error(result,"illegal ind for session")); + else if ( cclib_parsehash(&MUSIG[myind]->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)); + //fprintf(stderr, "COMMIT: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind); + MUSIG[myind]->numcommits++; + if ( MUSIG[myind]->numcommits >= MUSIG[myind]->num && 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[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; + if ( n == 5 ) + MUSIG[myind]->numnonces = 1; + 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)")); + } + 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")); - return(result); + static secp256k1_context *ctx; + 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 ( n > 3 ) + myind = juint(jitem(params,3),0); + else if ( n == 3 ) + myind = 0; + if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + 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[myind]->num ) + return(cclib_error(result,"illegal ind for session")); + else if ( musig_parsepubkey(ctx,MUSIG[myind]->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) + */ + MUSIG[myind]->numnonces++; + //fprintf(stderr, "NONCE: struct_size.%li using_struct.%i added_index.%i numnounces.%i num.%i\n",MUSIG.size(), myind, ind, MUSIG[myind]->numnonces, MUSIG[myind]->num); + if ( MUSIG[myind]->numnonces < MUSIG[myind]->num ) + { + result.push_back(Pair("status","not enough nonces")); + result.push_back(Pair("result","success")); + return(result); + } + for (i=0; inum; 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 + * 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[myind]->session,MUSIG[myind]->signer_data,MUSIG[myind]->num,NULL,NULL) > 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[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]->myind)); + result.push_back(Pair("partialsig",str)); + result.push_back(Pair("result","success")); + if ( n == 5 ) + MUSIG[myind]->numpartials = 1; + 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_partialsign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - return(result); -} - -UniValue musig_sigcombine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result","success")); - return(result); + static secp256k1_context *ctx; + UniValue result(UniValue::VOBJ); int32_t i,ind,n,myind; 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 ( n > 3 ) + myind = juint(jitem(params,3),0); + else if ( n == 3 ) + myind = 0; + if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 ) + return(cclib_error(result,"error parsing pkhash")); + 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[myind]->num ) + return(cclib_error(result,"illegal ind for session")); + else if ( cclib_parsehash(psig,jitem(params,2),32) < 0 ) + return(cclib_error(result,"error parsing psig")); + 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)); + //fprintf(stderr, "SIG: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind); + MUSIG[myind]->numpartials++; + if ( MUSIG[myind]->numpartials >= MUSIG[myind]->num && 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 ) + { + 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[myind]->partial_sig[MUSIG[myind]->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")); } +//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")); - 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 ( cclib_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 ( cclib_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 @@ -302,7 +774,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 ) @@ -312,13 +784,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; @@ -329,8 +803,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)); @@ -339,7 +829,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 ca05226d3..2daa1d0c7 100644 --- a/src/cc/rogue/main.c +++ b/src/cc/rogue/main.c @@ -30,7 +30,7 @@ extern char Gametxidstr[67]; #define SATOSHIDEN ((uint64_t)100000000L) #define dstr(x) ((double)(x) / SATOSHIDEN) #define KOMODO_ASSETCHAIN_MAXLEN 65 -char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],IPADDRESS[100]; #ifndef _BITS256 #define _BITS256 @@ -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); @@ -583,9 +587,9 @@ char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char * return(chunk.memory); } -uint16_t _komodo_userpass(char *username,char *password,FILE *fp) +uint16_t _komodo_userpass(char *username, char *password, FILE *fp) { - char *rpcuser,*rpcpassword,*str,line[8192]; uint16_t port = 0; + char *rpcuser,*rpcpassword,*str,*ipaddress,line[8192]; uint16_t port = 0; rpcuser = rpcpassword = 0; username[0] = password[0] = 0; while ( fgets(line,sizeof(line),fp) != 0 ) @@ -602,13 +606,18 @@ uint16_t _komodo_userpass(char *username,char *password,FILE *fp) port = atoi(parse_conf_line(str,(char *)"rpcport")); //fprintf(stderr,"rpcport.%u in file\n",port); } + else if ( (str= strstr(line,(char *)"ipaddress")) != 0 ) + { + ipaddress = parse_conf_line(str,(char *)"ipaddress"); + strcpy(IPADDRESS,ipaddress); + } } if ( rpcuser != 0 && rpcpassword != 0 ) { strcpy(username,rpcuser); strcpy(password,rpcpassword); } - //printf("rpcuser.(%s) rpcpassword.(%s) KMDUSERPASS.(%s) %u\n",rpcuser,rpcpassword,KMDUSERPASS,port); + //printf("rpcuser.(%s) rpcpassword.(%s) %u ipaddress.%s\n",rpcuser,rpcpassword,port,ipaddress); if ( rpcuser != 0 ) free(rpcuser); if ( rpcpassword != 0 ) @@ -688,7 +697,7 @@ char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) params = (char *)"[]"; if ( strlen(params) < sizeof(postdata)-128 ) { - sprintf(url,(char *)"http://127.0.0.1:%u",port); + sprintf(url,(char *)"http://%s:%u",IPADDRESS,port); sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,USERPASS); retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); @@ -715,12 +724,21 @@ void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_ } else { + static FILE *fp; + if ( fp == 0 ) + fp = fopen("keystrokes.log","a"); sprintf(params,"[\"keystrokes\",\"17\",\"[%%22%s%%22,%%22%s%%22]\"]",Gametxidstr,hexstr); if ( (retstr= komodo_issuemethod(USERPASS,"cclib",params,ROGUE_PORT)) != 0 ) { - //fprintf(stderr,"KEYSTROKES.(%s)\n",retstr); + if ( fp != 0 ) + { + fprintf(fp,"%s\n",params); + fprintf(fp,"%s\n",retstr); + fflush(fp); + } free(retstr); } + sleep(1); } } } @@ -794,7 +812,9 @@ int main(int argc, char **argv, char **envp) } ASSETCHAINS_SYMBOL[j++] = 0; ROGUE_PORT = komodo_userpass(userpass,ASSETCHAINS_SYMBOL); - printf("ASSETCHAINS_SYMBOL.(%s) port.%u (%s)\n",ASSETCHAINS_SYMBOL,ROGUE_PORT,USERPASS); sleep(1); + if ( IPADDRESS[0] == 0 ) + strcpy(IPADDRESS,"127.0.0.1"); + printf("ASSETCHAINS_SYMBOL.(%s) port.%u (%s) IPADDRESS.%s \n",ASSETCHAINS_SYMBOL,ROGUE_PORT,USERPASS,IPADDRESS); sleep(1); if ( argc == 2 && (fp=fopen(argv[1],"rb")) == 0 ) { seed = atol(argv[1]); @@ -813,5 +833,3 @@ int main(int argc, char **argv, char **envp) return(rogue(argc,argv,envp)); } } - - 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/rogue.c b/src/cc/rogue/rogue.c index e8de063de..53f6da353 100644 --- a/src/cc/rogue/rogue.c +++ b/src/cc/rogue/rogue.c @@ -560,13 +560,15 @@ playit(struct rogue_state *rs) } else { - if ( rs->needflush != 0 && rs->num > 8000 ) + if ( rs->needflush != 0 && rs->num > 1000 ) { if ( flushkeystrokes(rs) == 0 ) rs->needflush = 0; } } } + if ( rs->guiflag != 0 ) + flushkeystrokes(rs); endit(0); } diff --git a/src/cc/rogue/state.c b/src/cc/rogue/state.c index 7a0e2e4c6..b0176a042 100644 --- a/src/cc/rogue/state.c +++ b/src/cc/rogue/state.c @@ -1432,7 +1432,7 @@ rs_write_object(struct rogue_state *rs,FILE *savef, THING *o) if ( o->_o._o_packch != 0 ) { item = &rs->P.roguepack[rs->P.packsize]; - if ( 0 && pstats.s_hpt <= 0 ) + if ( 1 && pstats.s_hpt <= 0 ) { //fprintf(stderr,"KILLED\n"); rs->P.gold = -1; diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 57ce1e14b..aee151530 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -472,12 +472,25 @@ int32_t rogue_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint int32_t rogue_playerdataspend(CMutableTransaction &mtx,uint256 playertxid,int32_t vout,uint256 origplayergame) { - int64_t txfee = 10000; + int64_t txfee = 10000; CTransaction tx; uint256 hashBlock; if ( CCgettxout(playertxid,vout,1) == 1 ) // not sure if this is enough validation { mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); return(0); - } else return(-1); + } + else + { + vout = 0; + if ( myGetTransaction(playertxid,tx,hashBlock) != 0 && tx.vout[vout].nValue == 1 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( CCgettxout(playertxid,vout,1) == 1 ) // not sure if this is enough validation + { + mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); + return(0); + } + } + return(-1); + } } int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) @@ -505,7 +518,7 @@ int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke } if ( matches == 1 ) { - if ( myIsutxo_spent(spenttxid,gametxid,maxplayers+i+1) < 0 ) + if ( 1 || myIsutxo_spent(spenttxid,gametxid,maxplayers+i+1) < 0 ) { numvouts = matchtx.vout.size(); //fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); @@ -532,6 +545,7 @@ int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke return(-2); } txid = spenttxid; + //fprintf(stderr,"next txid.%s/v%d\n",txid.GetHex().c_str(),spentvini); if ( spentvini != 0 ) return(-3); if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) @@ -575,7 +589,7 @@ int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke else { fprintf(stderr,"already played\n"); - return(-5); + return(-6); } } return(-1); @@ -833,12 +847,14 @@ 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); *numkeysp = 0; seed = 0; + num = numkeys = 0; + playertxid = zeroid; if ( (err= rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) { if ( rogue_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,rogueaddr,numplayers,symbol,pname) == 0 ) @@ -852,21 +868,24 @@ char *rogue_extractgame(char *str,int32_t *numkeysp,std::vector &newdat for (i=0; i &newdat } if ( endP.gold <= 0 || endP.hitpoints <= 0 || (endP.strength&0xffff) <= 0 || endP.level <= 0 || endP.experience <= 0 || endP.dungeonlevel <= 0 ) { - fprintf(stderr,"zero value character was killed -> no playerdata\n"); + //fprintf(stderr,"zero value character was killed -> no playerdata\n"); newdata.resize(0); + //P.gold = (P.gold * 8) / 10; + if ( keystrokes != 0 ) + { + free(keystrokes); + keystrokes = 0; + *numkeysp = 0; + } + } + else + { + sprintf(str,"extracted $$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); + fprintf(stderr,"%s\n",str); + *numkeysp = numkeys; + return(keystrokes); } - sprintf(str,"extracted $$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - fprintf(stderr,"%s\n",str); } else num = 0; - } else fprintf(stderr,"extractgame: couldnt find baton\n"); + } + else + { + fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p\n",keystrokes); + if ( keystrokes != 0 ) + free(keystrokes), keystrokes = 0; + } } else fprintf(stderr,"extractgame: invalid game\n"); - *numkeysp = numkeys; - return(keystrokes); + //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); + return(0); } UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) @@ -914,7 +951,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; @@ -933,6 +970,77 @@ UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +int32_t rogue_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) +{ + static uint32_t good,bad; static uint256 prevgame; + char str[512],*keystrokes,rogueaddr[64],str2[67]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed,mult = 10; CPubKey roguepk; struct rogue_player P; + *cashoutp = 0; + roguepk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,rogueaddr,roguepk,pk); + //fprintf(stderr,"call extractgame\n"); + if ( (keystrokes= rogue_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,rogueaddr)) != 0 ) + { + //fprintf(stderr,"numkeys.%d rogue_extractgame %s\n",numkeys,gametxid.GetHex().c_str()); + free(keystrokes); + //fprintf(stderr,"extracted.(%s)\n",str); + for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); + } + *cashoutp = 0; + return(0); + } + } + if ( gametxid != prevgame ) + { + prevgame = gametxid; + bad++; + fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); + fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,rogueaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); + } + } + //fprintf(stderr,"no keys rogue_extractgame %s\n",gametxid.GetHex().c_str()); + return(-1); +} + UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,char *method) { //vin0 -> highlander vout from creategame TCBOO @@ -947,7 +1055,7 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param // vout0 -> 1% ingame gold // get any playerdata, get all keystrokes, replay game and compare final state CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,numkeys,maxplayers,batonht,batonvout; char myrogueaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,roguepk; uint8_t player[10000],mypriv[32],funcid; + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char myrogueaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,roguepk; uint8_t player[10000],mypriv[32],funcid; struct CCcontract_info *cpTokens, tokensC; if ( txfee == 0 ) @@ -961,12 +1069,12 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param if ( strcmp(method,"bailout") == 0 ) { funcid = 'Q'; - mult = 100000; + mult = 10; //100000; } else { funcid = 'H'; - mult = 200000; + mult = 20; //200000; } if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { @@ -991,7 +1099,7 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param { num = rogue_replay2(player,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); if ( keystrokes != 0 ) - free(keystrokes); + free(keystrokes), keystrokes = 0; } else num = 0; mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript())); mtx.vin.push_back(CTxIn(gametxid,1+maxplayers+regslot,CScript())); @@ -1005,22 +1113,26 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param newdata[i] = player[i]; ((uint8_t *)&P)[i] = player[i]; } - if ( 0 && (P.gold <= 0 || P.hitpoints <= 0 || (P.strength&0xffff) <= 0 || P.level <= 0 || P.experience <= 0 || P.dungeonlevel <= 0) ) + if ( (P.gold <= 0 || P.hitpoints <= 0 || (P.strength&0xffff) <= 0 || P.level <= 0 || P.experience <= 0 || P.dungeonlevel <= 0) ) { - fprintf(stderr,"zero value character was killed -> no playerdata\n"); + //fprintf(stderr,"zero value character was killed -> no playerdata\n"); newdata.resize(0); + //P.gold = (P.gold * 8) / 10; } else { - if ( maxplayers == 1 ) - mult /= 2; + //if ( maxplayers == 1 ) + // mult /= 2; cpTokens = CCinit(&tokensC, EVAL_TOKENS); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); - fprintf(stderr,"\nextracted $$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); if ( P.amulet != 0 ) mult *= 5; - cashout = (uint64_t)P.gold * mult; + dungeonlevel = P.dungeonlevel; + if ( P.amulet != 0 && dungeonlevel < 21 ) + dungeonlevel = 21; + cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; + fprintf(stderr,"\nextracted $$$gold.%d -> %.8f ROGUE hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); if ( funcid == 'H' && maxplayers > 1 ) { if ( (numplayers != maxplayers || (numplayers - rogue_playersalive(tmp,gametxid,maxplayers)) > 1) && P.amulet == 0 ) @@ -1036,7 +1148,6 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } } mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),roguepk)); - Myprivkey(mypriv); CCaddr1of2set(cp,roguepk,mypk,mypriv,myrogueaddr); CScript opret; @@ -1230,53 +1341,14 @@ UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } -int32_t rogue_playerdata_validate(uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,rogueaddr[64],str2[67]; int32_t i,numkeys; std::vector newdata; uint64_t seed; CPubKey roguepk; struct rogue_player P; - if ( gametxid == prevgame ) - return(0); - prevgame = gametxid; - 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 ) - { - free(keystrokes); - //fprintf(stderr,"extracted.(%s)\n",str); - if ( newdata == playerdata ) - { - good++; - fprintf(stderr,"%s good.%d bad.%d\n",gametxid.GetHex().c_str(),good,bad); - return(0); - } - newdata[10] = newdata[11] = playerdata[10] = playerdata[11] = 0; - if ( newdata == playerdata ) - { - good++; - fprintf(stderr,"%s matched after clearing maxstrength good.%d bad.%d\n",gametxid.GetHex().c_str(),good,bad); - return(0); - } - bad++; - for (i=0; i no playerdata\n"); - } - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,rogueaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); - } - return(-1); -} - bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { - CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid; int32_t i,maxplayers,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,tokenid,batontxid,playertxid,ptxid; int64_t buyin; std::vector playerdata,keystrokes; std::string symbol,pname; + CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid,tokentx=0; int32_t i,maxplayers,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,txid,tokenid,batontxid,playertxid,ptxid; int64_t buyin,cashout; std::vector playerdata,keystrokes; std::string symbol,pname; if ( strcmp(ASSETCHAINS_SYMBOL,"ROGUE") == 0 && height < 21274 ) return(true); if ( (numvouts= tx.vout.size()) > 1 ) { + txid = tx.GetHash(); scriptPubKey = tx.vout[numvouts-1].scriptPubKey; GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() > 2 ) @@ -1285,6 +1357,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C funcid = script[1]; if ( (e= script[0]) == EVAL_TOKENS ) { + tokentx = 1; if ( (funcid= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 ) { if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 ) @@ -1357,10 +1430,14 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C // verify pk belongs to this tx if ( playerdata.size() > 0 ) { - if ( rogue_playerdata_validate(ptxid,cp,playerdata,gametxid,pk) < 0 ) + if ( rogue_playerdata_validate(&cashout,ptxid,cp,playerdata,gametxid,pk) < 0 ) { - //fprintf(stderr,"ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); - } //else fprintf(stderr,"ht.%d playertxid.%s validated\n",height,ptxid.GetHex().c_str()); + fprintf(stderr,"ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); + } + if ( funcid == 'H' ) + cashout *= 2; + if ( tx.vout.size() > 3 ) // orig of 't' has 0 cashout + fprintf(stderr,"ht.%d txid.%s cashout %.8f vs vout2 %.8f\n",height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); } if ( funcid == 'Q' ) { diff --git a/src/komodo_cJSON.c b/src/komodo_cJSON.c old mode 100755 new mode 100644 diff --git a/src/komodo_cJSON.h b/src/komodo_cJSON.h old mode 100755 new mode 100644 diff --git a/src/komodo_jumblr.h b/src/komodo_jumblr.h old mode 100755 new mode 100644 diff --git a/src/musigtest.py b/src/musigtest.py new file mode 100755 index 000000000..a452b7e97 --- /dev/null +++ b/src/musigtest.py @@ -0,0 +1,200 @@ +#!/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 = float(input('Enter amount to send: ')) +if amount == 0: + sys.exit('Cannot send 0 coins. Exiting.') +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, i]) + commitments.append(rpc.cclib("session", "18", tmp)['commitment']) + i = i + 1 + +print("Created commitments sucessfully... Sending to all signers.") + +i = 0 +nonces = [] +for pubkey in pubkeys: + ret = rpc.setpubkey(pubkey) + n = 0 + for commitment in commitments: + tmp = str([pkhash, n, commitment, i]) + ret = rpc.cclib("commit", "18", tmp) + try: + nonces.append(ret['nonce']) + except: + x = 1 + n = n + 1 + i = i + 1 + +print("Created nounce's sucessfully... Sending to all signers.") + +i = 0 +partialsigs = [] +for pubkey in pubkeys: + ret = rpc.setpubkey(pubkey) + n = 0 + for nonce in nonces: + tmp = str([pkhash, n, nonce, i]) + ret = rpc.cclib("nonce", "18", tmp) + try: + partialsigs.append(ret['partialsig']) + except: + x = 1 + n = n + 1 + i = i + 1 + +print("Created partial sigs sucessfully... Sending to all signers.") + +i = 0 +combinedsigs = [] +for pubkey in pubkeys: + ret = rpc.setpubkey(pubkey) + n = 0 + for partialsig in partialsigs: + tmp = str([pkhash, n, partialsig, i]) + ret = rpc.cclib("partialsig", "18", tmp) + try: + combinedsigs.append(ret['combinedsig']) + except: + x = 1 + n = n + 1 + i = i + 1 + +print("Created combined sigs sucessfully... Verifying.") + +tmp = str([msg, combinedpk, combinedsigs[0]]) +ret = rpc.cclib("verify", "18", tmp) + +if ret['result'] != "success": + print(ret) + sys.exit('Could not verify signature.') + +print('Verified... Attempting to send.') + +tmp = str([senttxid, scriptPubKey, combinedsigs[0]]) +ret = rpc.cclib("spend", "18", tmp) + +if ret['result'] != "success": + print(ret) + sys.exit('Could not create spend transaction.') + +try: + ret = rpc.sendrawtransaction(ret['hex']) +except: + sys.exit('Could not send transaction.') + +print('Spent txid: ' + ret) 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; } diff --git a/src/uthash.h b/src/uthash.h old mode 100755 new mode 100644 diff --git a/src/utlist.h b/src/utlist.h old mode 100755 new mode 100644 diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0ed2f866c..0e0ab9906 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5308,7 +5308,7 @@ UniValue setpubkey(const UniValue& params, bool fHelp) char Raddress[64]; uint8_t pubkey33[33]; - if ( NOTARY_PUBKEY33[0] == 0 ) + if ( NOTARY_PUBKEY33[0] == 0 || (strcmp(ASSETCHAINS_SYMBOL, "MUSIG") == 0) ) { if (strlen(params[0].get_str().c_str()) == 66) {