Browse Source

Merge branch 'FSM' of https://github.com/jl777/komodo into jl777-FSM

pull/4/head
blackjok3r 5 years ago
parent
commit
5e91fa1632
  1. 22
      .gitignore
  2. 4
      .gitlab-ci.yml
  3. 1
      configure.ac
  4. 1
      depends/packages/boost.mk
  5. 16
      depends/packages/libsodium.mk
  6. 6
      depends/packages/openssl.mk
  7. 8
      depends/packages/rust.mk
  8. 14
      src/Makefile.am
  9. 18
      src/assetchains.json
  10. 2
      src/cc/CCinclude.h
  11. 38
      src/cc/Makefile_rogue
  12. 4
      src/cc/assets.cpp
  13. 195
      src/cc/cclib.cpp
  14. 0
      src/cc/dapps/cJSON.c
  15. 3269
      src/cc/dilithium.c
  16. 475
      src/cc/dilithium.h
  17. 2
      src/cc/faucet.cpp
  18. 2
      src/cc/makecclib
  19. 40
      src/cc/makerogue
  20. 868
      src/cc/musig.cpp
  21. 10
      src/cc/rogue/Makefile.in
  22. 222
      src/cc/rogue/Makefile_win
  23. 270
      src/cc/rogue/config.h
  24. 8
      src/cc/rogue/cursesd.c
  25. 6
      src/cc/rogue/cursesd.h
  26. 15
      src/cc/rogue/init.c
  27. 12
      src/cc/rogue/io.c
  28. 575
      src/cc/rogue/main.c
  29. 10
      src/cc/rogue/mdport.c
  30. 179
      src/cc/rogue/pack.c
  31. 2
      src/cc/rogue/rip.c
  32. 90
      src/cc/rogue/rogue.c
  33. 8
      src/cc/rogue/rogue.h
  34. 2
      src/cc/rogue/rogue_player.h
  35. 3
      src/cc/rogue/state.c
  36. 381
      src/cc/rogue_rpc.cpp
  37. 3
      src/cc/sudoku.cpp
  38. 24
      src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h
  39. 6
      src/komodo_bitcoind.h
  40. 0
      src/komodo_cJSON.c
  41. 0
      src/komodo_cJSON.h
  42. 11
      src/komodo_gateway.h
  43. 0
      src/komodo_jumblr.h
  44. 200
      src/musigtest.py
  45. 4
      src/secp256k1/Makefile.am
  46. 13
      src/secp256k1/include/secp256k1.h
  47. 502
      src/secp256k1/include/secp256k1_musig.h
  48. 129
      src/secp256k1/include/secp256k1_schnorrsig.h
  49. 59
      src/secp256k1/src/ecmult.h
  50. 23
      src/secp256k1/src/ecmult_const.h
  51. 273
      src/secp256k1/src/ecmult_const_impl.h
  52. 1176
      src/secp256k1/src/ecmult_impl.h
  53. 2
      src/secp256k1/src/modules/ecdh/main_impl.h
  54. 17
      src/secp256k1/src/modules/musig/Makefile.am.include
  55. 166
      src/secp256k1/src/modules/musig/example.c
  56. 631
      src/secp256k1/src/modules/musig/main_impl.h
  57. 758
      src/secp256k1/src/modules/musig/tests_impl.h
  58. 9
      src/secp256k1/src/modules/schnorrsig/Makefile.am.include
  59. 339
      src/secp256k1/src/modules/schnorrsig/main_impl.h
  60. 727
      src/secp256k1/src/modules/schnorrsig/tests_impl.h
  61. 118
      src/secp256k1/src/scalar.h
  62. 25
      src/secp256k1/src/scalar_4x64.h
  63. 1057
      src/secp256k1/src/scalar_4x64_impl.h
  64. 24
      src/secp256k1/src/scalar_8x32.h
  65. 838
      src/secp256k1/src/scalar_8x32_impl.h
  66. 340
      src/secp256k1/src/scalar_impl.h
  67. 20
      src/secp256k1/src/scalar_low.h
  68. 126
      src/secp256k1/src/scalar_low_impl.h
  69. 40
      src/secp256k1/src/scratch.h
  70. 87
      src/secp256k1/src/scratch_impl.h
  71. 31
      src/secp256k1/src/secp256k1.c
  72. 18
      src/secp256k1/src/tests.c
  73. 2
      src/secp256k1/src/tests_exhaustive.c
  74. 0
      src/uthash.h
  75. 0
      src/utlist.h
  76. 7
      src/wallet/rpcwallet.cpp
  77. 9
      zcutil/build-mac.sh
  78. 8
      zcutil/build-win.sh
  79. 9
      zcutil/build.sh

22
.gitignore

@ -132,3 +132,25 @@ src/cc/rogue/rogue
src/cc/rogue/rogue.so
src/cc/rogue/test.zip
src/rogue.530623577502174316.0
src/rogue.530623577502174316.pack
src/rogue.530623577502174316.player
src/checkfile
src/log
src/foo.zip
src/cc/rogue/config.h
src/cc/rogue/config.h
src/ROGUE.conf
src/rogue.scr
src/cc/rogue/confdefs.h

4
.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}

1
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])

1
depends/packages/boost.mk

@ -1,4 +1,3 @@
package=boost
$(package)_version=1_66_0
$(package)_download_path=https://dl.bintray.com/boostorg/release/1.66.0/source

16
depends/packages/libsodium.mk

@ -1,12 +1,3 @@
ifeq ($(build_os),darwin)
package=libsodium
$(package)_version=1.0.11
$(package)_download_path=https://supernetorg.bintray.com/misc
$(package)_file_name=libsodium-1.0.11.tar.gz
$(package)_sha256_hash=a14549db3c49f6ae2170cbbf4664bd48ace50681045e8dbea7c8d9fb96f9c765
$(package)_dependencies=
$(package)_config_opts=
else
package=libsodium
$(package)_version=1.0.15
$(package)_download_path=https://download.libsodium.org/libsodium/releases/old
@ -14,6 +5,13 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4
$(package)_dependencies=
$(package)_config_opts=
ifeq ($(build_os),darwin)
define $(package)_set_vars
$(package)_build_env=MACOSX_DEPLOYMENT_TARGET="10.11"
$(package)_cc=clang
$(package)_cxx=clang++
endef
endif
define $(package)_preprocess_cmds

6
depends/packages/openssl.mk

@ -1,8 +1,8 @@
package=openssl
$(package)_version=1.1.0h
$(package)_version=1.1.1a
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=5835626cde9e99656585fc7aaa2302a73a7e1340bf8c14fd635a62c66802a517
$(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
@ -92,7 +92,7 @@ $(package)_config_opts_i686_mingw32=mingw
endef
define $(package)_preprocess_cmds
sed -i.old "/define DATE/d" util/mkbuildinf.pl && \
sed -i.old 's/built on: $date/built on: not available/' util/mkbuildinf.pl && \
sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure
endef

8
depends/packages/rust.mk

@ -1,13 +1,13 @@
package=rust
$(package)_version=1.28.0
$(package)_version=1.32.0
$(package)_download_path=https://static.rust-lang.org/dist
$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz
$(package)_sha256_hash_linux=2a1390340db1d24a9498036884e6b2748e9b4b057fc5219694e298bdaa37b810
$(package)_sha256_hash_linux=e024698320d76b74daf0e6e71be3681a1e7923122e3ebd03673fcac3ecc23810
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
$(package)_sha256_hash_darwin=5d7a70ed4701fe9410041c1eea025c95cad97e5b3d8acc46426f9ac4f9f02393
$(package)_sha256_hash_darwin=f0dfba507192f9b5c330b5984ba71d57d434475f3d62bd44a39201e36fa76304
$(package)_file_name_mingw32=rust-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz
$(package)_sha256_hash_mingw32=55c07426f791c51c8a2b6934b35784175c4abb4e03f123f3e847109c4dc1ad8b
$(package)_sha256_hash_mingw32=358e1435347c67dbf33aa9cad6fe501a833d6633ed5d5aa1863d5dffa0349be9
ifeq ($(build_os),darwin)
$(package)_file_name=$($(package)_file_name_darwin)

14
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,11 +579,14 @@ komodod_LDADD += \
$(LIBZCASH_LIBS)
if TARGET_DARWIN
komodod_LDADD += libcc.dylib # -lncurses
else
komodod_LDADD += libcc.so # -lncurses
komodod_LDADD += libcc.dylib $(LIBSECP256K1)
endif
if TARGET_WINDOWS
komodod_LDADD += libcc.dll $(LIBSECP256K1)
endif
if TARGET_LINUX
komodod_LDADD += libcc.so $(LIBSECP256K1)
endif
if ENABLE_PROTON
komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)

18
src/assetchains.json

@ -233,5 +233,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"
]
}
]

2
src/cc/CCinclude.h

@ -139,7 +139,7 @@ int32_t komodo_nextheight();
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout);
void CCclearvars(struct CCcontract_info *cp);
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params);
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr);
UniValue CClib_info(struct CCcontract_info *cp);
CBlockIndex *komodo_blockindex(uint256 hash);
CBlockIndex *komodo_chainactive(int32_t height);

38
src/cc/Makefile_rogue

@ -0,0 +1,38 @@
SHELL = /bin/sh
CC = gcc
CC_DARWIN = g++-6
CC_WIN = x86_64-w64-mingw32-gcc-posix
CFLAGS_DARWIN = -DBUILD_ROGUE -std=c++11 -arch x86_64 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib
CFLAGS = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared
CFLAGS_WIN = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/x86_64-w64-mingw32/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared
DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
$(info $(OS))
OS := $(shell uname -s)
$(info $(OS))
TARGET = librogue.so
TARGET_DARWIN = librogue.dylib
TARGET_WIN = librogue.dll
SOURCES = cclib.cpp
#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/
all: $(TARGET)
$(TARGET): $(SOURCES)
$(info Building cclib to src/)
ifeq ($(OS),Darwin)
$(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) -c $(SOURCES)
cp $(TARGET_DARWIN) ../libcc.dylib
else ifeq ($(HOST),x86_64-w64-mingw32)
$(info WINDOWS)
$(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES)
cp $(TARGET_WIN) ../libcc.dll
#else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host
else
$(info LINUX)
$(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES)
cp $(TARGET) ../libcc.so
endif
clean:
rm -rf $(TARGET)

4
src/cc/assets.cpp

@ -259,7 +259,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("invalid refund for cancelbuy");
preventCCvins = 3;
preventCCvouts = 0;
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origNormalAddr);
//fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origNormalAddr);
break;
case 'B': // fillbuy:
@ -305,7 +305,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
}
}
fprintf(stderr,"fillbuy validated\n");
//fprintf(stderr,"fillbuy validated\n");
break;
//case 'e': // selloffer
// break; // disable swaps

195
src/cc/cclib.cpp

@ -36,6 +36,8 @@ std::string MYCCLIBNAME = (char *)"rogue";
#else
#define EVAL_SUDOKU 17
#define EVAL_MUSIG 18
#define EVAL_DILITHIUM 19
std::string MYCCLIBNAME = (char *)"sudoku";
#endif
@ -70,6 +72,21 @@ CClib_methods[] =
{ (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"pending", (char *)"<no args>", 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, 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 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
};
@ -98,11 +115,66 @@ UniValue sudoku_txidinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params
UniValue sudoku_generate(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
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_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
UniValue CClib_method(struct CCcontract_info *cp,char *method,cJSON *params)
cJSON *cclib_reparse(int32_t *nump,char *jsonstr) // assumes origparams will be freed by caller
{
cJSON *params; char *newstr; int32_t i,j;
*nump = 0;
if ( jsonstr != 0 )
{
if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' )
{
jsonstr[strlen(jsonstr)-1] = 0;
jsonstr++;
}
newstr = (char *)malloc(strlen(jsonstr)+1);
for (i=j=0; jsonstr[i]!=0; i++)
{
if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' )
{
newstr[j++] = '"';
i += 2;
}
else if ( jsonstr[i] == '\'' )
newstr[j++] = '"';
else newstr[j++] = jsonstr[i];
}
newstr[j] = 0;
params = cJSON_Parse(newstr);
if ( 0 && params != 0 )
printf("new.(%s) -> %s\n",newstr,jprint(params,0));
free(newstr);
*nump = cJSON_GetArraySize(params);
//free(origparams);
} else params = 0;
return(params);
}
UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr)
{
UniValue result(UniValue::VOBJ); uint64_t txfee = 10000;
UniValue result(UniValue::VOBJ); uint64_t txfee = 10000; int32_t m; cJSON *params = cclib_reparse(&m,jsonstr);
//fprintf(stderr,"method.(%s) -> (%s)\n",jsonstr!=0?jsonstr:"",params!=0?jprint(params,0):"");
#ifdef BUILD_ROGUE
if ( cp->evalcode == EVAL_ROGUE )
{
@ -158,6 +230,57 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,cJSON *params)
return(result);
}
}
else if ( cp->evalcode == EVAL_MUSIG )
{
//printf("CClib_method params.%p\n",params);
if ( strcmp(method,"combine") == 0 )
return(musig_combine(txfee,cp,params));
else if ( strcmp(method,"calcmsg") == 0 )
return(musig_calcmsg(txfee,cp,params));
else if ( strcmp(method,"session") == 0 )
return(musig_session(txfee,cp,params));
else if ( strcmp(method,"commit") == 0 )
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,"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 )
return(musig_send(txfee,cp,params));
else if ( strcmp(method,"spend") == 0 )
return(musig_spend(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid musig method"));
result.push_back(Pair("method",method));
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
{
@ -196,10 +319,10 @@ UniValue CClib_info(struct CCcontract_info *cp)
return(result);
}
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params)
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr)
{
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx;
//printf("CClib params.%p\n",params);
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx; cJSON *params;
//printf("CClib params.(%s)\n",jsonstr!=0?jsonstr:"");
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
if ( cp->evalcode == CClib_methods[i].evalcode && strcmp(method,CClib_methods[i].method) == 0 )
@ -208,10 +331,12 @@ UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params)
{
result.push_back(Pair("result","success"));
result.push_back(Pair("method",CClib_methods[i].method));
params = cJSON_Parse(jsonstr);
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
free_json(params);
result.push_back(Pair("rawtx",rawtx));
return(result);
} else return(CClib_method(cp,method,params));
} else return(CClib_method(cp,method,jsonstr));
}
}
result.push_back(Pair("result","error"));
@ -278,7 +403,13 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
#ifdef BUILD_ROGUE
return(rogue_validate(cp,height,eval,tx));
#else
return(sudoku_validate(cp,height,eval,tx));
if ( cp->evalcode == EVAL_SUDOKU )
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
}
numvins = tx.vin.size();
@ -385,21 +516,6 @@ std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds)
return("");
}
/*UniValue FaucetInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey faucetpk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Faucet"));
cp = CCinit(&C,EVAL_FAUCET);
faucetpk = GetUnspendable(cp,0);
funding = AddFaucetInputs(cp,mtx,faucetpk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
return(result);
}*/
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params)
{
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@ -464,34 +580,14 @@ uint256 juint256(cJSON *obj)
return(revuint256(tmp));
}
cJSON *cclib_reparse(int32_t *nump,cJSON *origparams) // assumes origparams will be freed by caller
int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len)
{
cJSON *params; char *jsonstr,*newstr; int32_t i,j;
if ( (jsonstr= jprint(origparams,0)) != 0 )
char *hexstr;
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == len*2 )
{
if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' )
{
jsonstr[strlen(jsonstr)-1] = 0;
jsonstr++;
}
newstr = (char *)malloc(strlen(jsonstr)+1);
for (i=j=0; jsonstr[i]!=0; i++)
{
if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' )
{
newstr[j++] = '"';
i += 2;
} else newstr[j++] = jsonstr[i];
}
newstr[j] = 0;
params = cJSON_Parse(newstr);
if ( 0 && params != 0 )
printf("new.(%s) -> %s\n",newstr,jprint(params,0));
free(newstr);
*nump = cJSON_GetArraySize(params);
//free(origparams);
} else params = 0;
return(params);
decode_hex(hash32,len,hexstr);
return(0);
} else return(-1);
}
#ifdef BUILD_ROGUE
@ -533,5 +629,8 @@ cJSON *cclib_reparse(int32_t *nump,cJSON *origparams) // assumes origparams will
#else
#include "sudoku.cpp"
#include "musig.cpp"
#include "dilithium.c"
//#include "../secp256k1/src/modules/musig/example.c"
#endif

0
src/cc/dapps/cJSON.c

3269
src/cc/dilithium.c

File diff suppressed because one or more lines are too long

475
src/cc/dilithium.h

@ -0,0 +1,475 @@
#include <stdint.h>
/*
#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 <stdint.h>
//#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 <stdint.h>
//#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 <stdint.h>
//#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 <stdint.h>
#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 <stdint.h>
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

2
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 )

2
src/cc/makecclib

@ -1,2 +1,2 @@
#!/bin/sh
gcc -std=c++11 -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

40
src/cc/makerogue

@ -1,8 +1,38 @@
#!/bin/sh
cd rogue;
./configure # only need this first time
make; cd ..
gcc -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -o librogue.so -c cclib.cpp
#gcc -std=c++11 -fPIC -shared -o librogue.so cclib.o rogue/rogue.so
cp librogue.so ../libcc.so
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 && rm mingw32.zip
echo lib archive cleaned
cd ..
echo $PWD
if make -f Makefile_win "$@"; then
echo rogue.exe build SUCCESSFUL
cd ..
else
echo rogue.exe build FAILED
exit 1
fi
else
echo building rogue...
./configure
if make "$@"; then
echo rogue build SUCCESSFUL
cd ..
else
echo rogue build FAILED
exit 1
fi
fi
if make -f Makefile_rogue "$@"; then
echo ROGUE BUILD SUCCESSFUL
else
echo ROGUE BUILD FAILED
exit 1
fi

868
src/cc/musig.cpp

@ -0,0 +1,868 @@
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
/* first make a combined pk:
./komodo-cli -ac_name=MUSIG cclib combine 18 '["02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28","0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4"]'
{
"pkhash": "5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
"result": "success"
}
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": "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"]'
{
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
"result": "success"
}
the "msg" is what needs to be signed to create a valid spend
now on each signing node, a session needs to be created:
5 args: ind, numsigners, combined_pk, pkhash, message to be signed
on node with pubkey: 02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28
./komodo-cli -ac_name=MUSIG cclib session 18 '[0,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]'
{
"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"
}
*/
#define USE_BASIC_CONFIG
#define ENABLE_MODULE_MUSIG
#include "../secp256k1/src/basic-config.h"
#include "../secp256k1/include/secp256k1.h"
#include "../secp256k1/src/ecmult.h"
#include "../secp256k1/src/ecmult_gen.h"
typedef struct { unsigned char data[64]; } secp256k1_schnorrsig;
struct secp256k1_context_struct {
secp256k1_ecmult_context ecmult_ctx;
secp256k1_ecmult_gen_context ecmult_gen_ctx;
secp256k1_callback illegal_callback;
secp256k1_callback error_callback;
};
//#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 <struct musig_info *> 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; i<num; i++)
mp->commitment_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;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
return(opret);
}
uint8_t musig_sendopretdecode(CPubKey &pk,CScript scriptPubKey)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_MUSIG && f == 'x' )
{
return(f);
}
return(0);
}
CScript musig_spendopret(uint8_t funcid,CPubKey pk,std::vector<uint8_t> musig64)
{
CScript opret; uint8_t evalcode = EVAL_MUSIG;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk << musig64);
return(opret);
}
uint8_t musig_spendopretdecode(CPubKey &pk,std::vector<uint8_t> &musig64,CScript scriptPubKey)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk; ss >> musig64) != 0 && e == EVAL_MUSIG && f == 'y' )
{
return(f);
}
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;
data << E_MARSHAL(ss << prevhash << prevn << vout << pk);
hash = Hash(data.begin(),data.end());
memcpy(msg,&hash,sizeof(hash));
return(0);
}
int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey)
{
CTransaction vintx; uint256 hashBlock; int32_t numvouts; CTxOut vout; CPubKey pk;
memset(msg,0,32);
if ( myGetTransaction(sendtxid,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
{
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
{
vout.nValue = vintx.vout[MUSIG_PREVN].nValue - MUSIG_TXFEE;
vout.scriptPubKey = scriptPubKey;
return(musig_msghash(msg,sendtxid,MUSIG_PREVN,vout,pk));
}
}
return(-1);
}
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
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 )
{
sendtxid = juint256(jitem(params,0));
scriptstr = jstr(jitem(params,1),0);
if ( is_hexstr(scriptstr,0) != 0 )
{
CScript scriptPubKey;
scriptPubKey.resize(strlen(scriptstr)/2);
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
musig_prevoutmsg(msg,sendtxid,scriptPubKey);
for (i=0; i<32; i++)
{
sprintf(&str[i<<1],"%02x",msg[i]);
if ( msg[i] == 0 )
zeros++;
}
str[64] = 0;
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"));
}
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static secp256k1_context *ctx;
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
UniValue result(UniValue::VOBJ); CPubKey pk; int32_t i,n; uint8_t pkhash[32]; char *hexstr,str[67]; secp256k1_pubkey combined_pk,spk; std::vector<secp256k1_pubkey> pubkeys;
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
//fprintf(stderr,"n.%d args.(%s)\n",n,jprint(params,0));
for (i=0; i<n; i++)
{
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 )
{
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&combined_pk,SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
{
for (i=0; i<32; i++)
sprintf(&str[i<<1],"%02x",pkhash[i]);
str[64] = 0;
result.push_back(Pair("pkhash",str));
for (i=0; i<33; i++)
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
str[66] = 0;
result.push_back(Pair("combined_pk",str));
result.push_back(Pair("result","success"));
return(result);
} else return(cclib_error(result,"error serializeing combined_pk"));
} else return(cclib_error(result,"error combining pukbeys"));
} else return(cclib_error(result,"need pubkeys params"));
}
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
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)
{
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)
{
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; i<MUSIG[myind]->num; 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_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
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)
{
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
UniValue musig_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);
}
UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ); int32_t n; char *hexstr; std::string rawtx; int64_t amount; CPubKey musigpk,mypk;
if ( txfee == 0 )
txfee = MUSIG_TXFEE;
mypk = pubkey2pk(Mypubkey());
musigpk = GetUnspendable(cp,0);
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n == 2 && (hexstr= jstr(jitem(params,0),0)) != 0 && is_hexstr(hexstr,0) == 66 )
{
CPubKey pk(ParseHex(hexstr));
amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049;
if ( amount >= 3*txfee && AddNormalinputs(mtx,mypk,amount+2*txfee,64) >= amount+2*txfee )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount+txfee,musigpk));
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_sendopret('x',pk));
return(musig_rawtxresult(result,rawtx));
} else return(cclib_error(result,"couldnt find funds or less than 0.0003"));
} else return(cclib_error(result,"must have 2 params: pk, amount"));
} else return(cclib_error(result,"not enough parameters"));
}
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 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 )
{
if ( n == 3 )
{
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 ( txfee == 0 )
txfee = MUSIG_TXFEE;
mypk = pubkey2pk(Mypubkey());
std::vector<uint8_t> musig64(ParseHex(musigstr));
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;
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
{
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
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));
return(musig_rawtxresult(result,rawtx));
} else return(cclib_error(result,"couldnt parse pk or musig"));
} 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 sendtxid, scriptPubKey, musig"));
} else return(cclib_error(result,"params parse error"));
}
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
static secp256k1_context *ctx;
secp256k1_pubkey combined_pk; CPubKey pk,checkpk; secp256k1_schnorrsig musig; uint256 hashBlock; CTransaction vintx; int32_t numvouts; std::vector<uint8_t> musig64; uint8_t msg[32];
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
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 ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
{
if ( musig_spendopretdecode(checkpk,musig64,tx.vout[tx.vout.size()-1].scriptPubKey) == 'y' )
{
if ( pk == checkpk )
{
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
{
musig_prevoutmsg(msg,tx.vin[0].prevout.hash,tx.vout[0].scriptPubKey);
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
return eval->Invalid("failed schnorrsig_verify");
else return(true);
} else return eval->Invalid("couldnt parse pk or musig");
} else return eval->Invalid("combined_pk didnt match send opret");
} else return eval->Invalid("failed decode musig spendopret");
} else return eval->Invalid("couldnt decode send opret");
} else return eval->Invalid("couldnt find vin0 tx");
}

10
src/cc/rogue/Makefile.in

@ -28,8 +28,8 @@ CC = @CC@
#CFLAGS=-O2
CFLAGS= @CFLAGS@ -fPIC
#LIBS=-lcurses
LIBS = @LIBS@
LIBS=-lcurses -lcurl
#LIBS = @LIBS@
#RM=rm -f
RM = rm -f
@ -128,9 +128,11 @@ MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c
#$(RM) rogue.so ; $(CC) -shared -o rogue.so cursesd.c $(OBJS1) $(OBJS2); $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(PROGRAM): $(HDRS) $(OBJS)
$(RM) rogue.so ; $(CC) -shared -o rogue.so $(OBJS1) $(OBJS2) -lcurses; $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
clean:
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so

222
src/cc/rogue/Makefile_win

@ -0,0 +1,222 @@
###############################################################################
#
# Makefile for rogue
#
# Rogue: Exploring the Dungeons of Doom
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
###############################################################################
###############################################################################
# Site configuration occurs beneath this comment
# Typically ./configure (autoconf tools) configures this section
# This section could be manually configured if autoconf/configure fails
###############################################################################
DISTNAME=rogue5.4.4
PACKAGE_TARNAME = rogue-5.4.4
PROGRAM=rogue
O=o
#CC=gcc
CC = x86_64-w64-mingw32-gcc
#CFLAGS=-O2
CFLAGS= -g -O2 -I./ncurses/include -I./ncurses/include/ncursesw -I../../../depends/x86_64-w64-mingw32/include
#LIBS=-lcurses
LIBS = -L./ncurses/lib -lncursesw -lcurl
#RM=rm -f
RM = rm -f
#GROFF=groff
GROFF = groff
#NROFF=nroff
NROFF = nroff
#TBL=tbl
TBL = tbl
#COLCRT=colcrt
COLCRT = colcrt
#SED=sed
SED = sed
#SCOREFILE=rogue54.scr
SCOREFILE = rogue.scr
#LOCKFILE=rogue54.lck
LOCKFILE = rogue.lck
#GROUPOWNER=games
GROUPOWNER =
#CPPFLAGS=-DHAVE_CONFIG_H
CPPFLAGS =-DHAVE_CONFIG_H
#DISTFILE = $(PROGRAM)
DISTFILE = $(DISTNAME)-x86_64-w64-mingw32
INSTALL=./install-sh
#INSTGROUP=-g games
INSTGROUP=
#INSTOWNER=-u root
INSTOWNER=
CHGRP=chgrp
MKDIR=mkdir
TOUCH=touch
RMDIR=rmdir
CHMOD=chmod
DESTDIR=
prefix=/usr/local
exec_prefix=${prefix}
datarootdir=${prefix}/share
datadir=${datarootdir}
bindir=${exec_prefix}/bin
mandir=${datarootdir}/man
docdir=${datarootdir}/doc/${PACKAGE_TARNAME}
man6dir = $(mandir)/man6
###############################################################################
# Site configuration occurs above this comment
# It should not be necessary to change anything below this comment
###############################################################################
HDRS = rogue.h extern.h score.h
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
mach_dep.$(O) rogue.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
move.$(O) new_level.$(O)
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
OBJS = main.$(O) $(OBJS1) $(OBJS2)
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
daemons.c fight.c init.c io.c list.c mach_dep.c \
main.c mdport.c misc.c monsters.c move.c new_level.c \
options.c pack.c passages.c potions.c rings.c rip.c \
rooms.c save.c scrolls.c state.c sticks.c things.c \
weapons.c wizard.c xcrypt.c
MISC_C = findpw.c scedit.c scmisc.c
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
$(PROGRAM).6
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
rogue.png rogue.desktop
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) $(CPPFLAGS) /c $*.c
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c
#$(RM) rogue.so ; $(CC) -shared -o rogue.so cursesd.c $(OBJS1) $(OBJS2); $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(PROGRAM): $(HDRS) $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@.exe
clean:
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
$(RM) $(DISTNAME)/*
-rmdir $(DISTNAME)
maintainer-clean:
$(RM) config.h
$(RM) Makefile
$(RM) config.status
$(RM) -r autom4te.cache
$(RM) config.log
$(RM) $(PROGRAM).scr $(PROGRAM).lck
stddocs:
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.6.in > rogue.6
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.me.in > rogue.me
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.html.in > rogue,html
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.doc.in > rogue.doc
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.cat.in > rogue.cat
dist.src:
$(MAKE) $(MAKEFILE) clean
mkdir $(DISTNAME)
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
tar cf $(DISTNAME)-src.tar $(DISTNAME)
gzip -f $(DISTNAME)-src.tar
rm -fr $(DISTNAME)
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
scmisc.o scedit.o:
$(CC) -O -c $(SF) $*.c
$(PROGRAM).doc: rogue.me
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
$(GROFF) -P-c -t -me -Tascii rogue.me | $(SED) -e 's/.\x08//g' > $(PROGRAM).doc ;\
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
tbl rogue.me | $(NROFF) -me | colcrt - > $(PROGRAM).doc ;\
fi
$(PROGRAM).cat: rogue.6
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
$(GROFF) -Tascii -man rogue.6 | $(SED) -e 's/.\x08//g' > $(PROGRAM).cat ;\
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
$(NROFF) -man rogue.6 | $(COLCRT) - > $(PROGRAM).cat ;\
fi
dist: clean $(PROGRAM)
tar cf $(DISTFILE).tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTFILE).tar
install: $(PROGRAM)
-$(TOUCH) test
-if test ! -f $(DESTDIR)$(SCOREFILE) ; then $(INSTALL) -m 0664 test $(DESTDIR)$(SCOREFILE) ; fi
-$(INSTALL) -m 0755 $(PROGRAM) $(DESTDIR)$(bindir)/$(PROGRAM)
-if test "x$(GROUPOWNER)" != "x" ; then \
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(SCOREFILE) ; \
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(bindir)/$(PROGRAM) ; \
$(CHMOD) 02755 $(DESTDIR)$(bindir)/$(PROGRAM) ; \
$(CHMOD) 0464 $(DESTDIR)$(SCOREFILE) ; \
fi
-if test -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(man6dir)/$(PROGRAM).6 ; fi
-if test ! -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(mandir)/$(PROGRAM).6 ; fi
-$(INSTALL) -m 0644 rogue.doc $(DESTDIR)$(docdir)/$(PROGRAM).doc
-$(INSTALL) -m 0644 rogue.html $(DESTDIR)$(docdir)/$(PROGRAM).html
-$(INSTALL) -m 0644 rogue.cat $(DESTDIR)$(docdir)/$(PROGRAM).cat
-$(INSTALL) -m 0644 LICENSE.TXT $(DESTDIR)$(docdir)/LICENSE.TXT
-$(INSTALL) -m 0644 rogue.me $(DESTDIR)$(docdir)/$(PROGRAM).me
-if test ! -f $(DESTDIR)$(LOCKFILE) ; then $(INSTALL) -m 0666 test $(DESTDIR)$(LOCKFILE) ; $(RM) $(DESTDIR)$(LOCKFILE) ; fi
-$(RM) test
uninstall:
-$(RM) $(DESTDIR)$(bindir)/$(PROGRAM)
-$(RM) $(DESTDIR)$(man6dir)/$(PROGRAM).6
-$(RM) $(DESTDIR)$(docdir)$(PROGRAM)/$(PROGRAM).doc
-$(RM) $(DESTDIR)$(LOCKFILE)
-$(RMDIR) $(DESTDIR)$(docdir)$(PROGRAM)
reinstall: uninstall install

270
src/cc/rogue/config.h

@ -1,270 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if scorefile is top scores, not top players */
#define ALLSCORES 1
/* Define if checktime feature should be enabled */
/* #undef CHECKTIME */
/* Define to group owner of setgid executable */
/* #undef GROUPOWNER */
/* Define to 1 if you have the `alarm' function. */
#define HAVE_ALARM 1
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
/* Define to 1 if libcurses is requested */
#define HAVE_CURSES_H 1
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
/* #undef HAVE_DOPRNT */
/* Define to 1 if you have the `erasechar' function. */
#define HAVE_ERASECHAR 1
/* Define if ncurses has ESCDELAY variable */
#define HAVE_ESCDELAY 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `fork' function. */
#define HAVE_FORK 1
/* Define to 1 if you have the `getgid' function. */
#define HAVE_GETGID 1
/* Define to 1 if you have the `getloadavg' function. */
#define HAVE_GETLOADAVG 1
/* Define to 1 if you have the `getpass' function. */
#define HAVE_GETPASS 1
/* Define to 1 if you have the `getpwuid' function. */
#define HAVE_GETPWUID 1
/* Define to 1 if you have the `getuid' function. */
#define HAVE_GETUID 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `killchar' function. */
#define HAVE_KILLCHAR 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the `loadav' function. */
/* #undef HAVE_LOADAV */
/* Define to 1 if `lstat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if libncurses is requested */
/* #undef HAVE_NCURSES_H */
/* Define to 1 if you have the <ncurses/term.h> header file. */
/* #undef HAVE_NCURSES_TERM_H */
/* Define to 1 if you have the `nlist' function. */
/* #undef HAVE_NLIST */
/* Define to 1 if you have the <nlist.h> header file. */
#define HAVE_NLIST_H 1
/* Define to 1 if you have the <process.h> header file. */
/* #undef HAVE_PROCESS_H */
/* Define to 1 if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1
/* Define to 1 if you have the `setenv' function. */
#define HAVE_SETENV 1
/* Define to 1 if you have the `setgid' function. */
#define HAVE_SETGID 1
/* Define to 1 if you have the `setregid' function. */
#define HAVE_SETREGID 1
/* Define to 1 if you have the `setresgid' function. */
/* #undef HAVE_SETRESGID */
/* Define to 1 if you have the `setresuid' function. */
/* #undef HAVE_SETRESUID */
/* Define to 1 if you have the `setreuid' function. */
#define HAVE_SETREUID 1
/* Define to 1 if you have the `setuid' function. */
#define HAVE_SETUID 1
/* Define to 1 if you have the `spawnl' function. */
/* #undef HAVE_SPAWNL */
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if stdbool.h conforms to C99. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/utsname.h> header file. */
#define HAVE_SYS_UTSNAME_H 1
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the <term.h> header file. */
#define HAVE_TERM_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <utmp.h> header file. */
#define HAVE_UTMP_H 1
/* Define to 1 if you have the `vfork' function. */
#define HAVE_VFORK 1
/* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */
/* Define to 1 if you have the `vprintf' function. */
#define HAVE_VPRINTF 1
/* Define to 1 if `fork' works. */
#define HAVE_WORKING_FORK 1
/* Define to 1 if `vfork' works. */
#define HAVE_WORKING_VFORK 1
/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1
/* Define to 1 if you have the `_spawnl' function. */
/* #undef HAVE__SPAWNL */
/* define if we should use program's load average function instead of system
*/
/* #undef LOADAV */
/* Define to file to use for scoreboard lockfile */
#define LOCKFILE "rogue.lck"
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
/* Define to include wizard mode */
/* #undef MASTER */
/* Define if maxusers feature should be enabled */
/* #undef MAXLOAD */
/* Define if maxusers feature should be enabled */
/* #undef MAXUSERS */
/* kernel file to pass to nlist() when reading load average (unlikely to work)
*/
/* #undef NAMELIST */
/* word for the number of scores to store in scoreboard */
#define NUMNAME "Ten"
/* number of scores to store in scoreboard */
#define NUMSCORES 10
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "yendor@rogueforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "Rogue"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Rogue 5.4.4"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "rogue"
/* Define to the version of this package. */
#define PACKAGE_VERSION "5.4.4"
/* Define crypt(3) wizard mode password */
/* #undef PASSWD */
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to file to use for scoreboard */
#define SCOREFILE "rogue.scr"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
/* #undef TM_IN_SYS_TIME */
/* define if we should use program's user counting function instead of
system's */
/* #undef UCOUNT */
/* utmp like file to pass to ucount() when counting online users (unlikely to
work) */
/* #undef UTMP */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef gid_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef pid_t */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef uid_t */
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */

8
src/cc/rogue/cursesd.c

@ -410,11 +410,13 @@ int32_t wgetnstr(WINDOW *win, char *str, int32_t n) // stub
return(0);
}
#ifndef __MINGW32__
int32_t getch(void)
{
fprintf(stderr,"unexpected and unsupported call to getch\n");
return(0);
}
#endif
int32_t md_readchar(void)
{
@ -422,3 +424,9 @@ int32_t md_readchar(void)
return(0);
}
char *unctrl(char c)
{
static char ctrlstr[5];
sprintf(ctrlstr,"^%%%02x",c);
return(ctrlstr);
}

6
src/cc/rogue/cursesd.h

@ -48,7 +48,10 @@ extern WINDOW *stdscr,*curscr;
extern int32_t ESCDELAY;
typedef char chtype;
#ifndef __MINGW32__
int32_t getch(void); // stub
#endif
int32_t md_readchar(void); // stub
WINDOW *initscr(void);
@ -123,9 +126,10 @@ int32_t wprintw(WINDOW *win,char *fmt,...);
int32_t mvprintw(int32_t y,int32_t x,char *fmt,...);
int32_t mvwprintw(WINDOW *win,int32_t y,int32_t x,char *fmt,...);
char *unctrl(char c);
#define A_CHARTEXT 0xff
#define baudrate() 9600
#define unctrl(a) "^x"
#define getmaxx(a) COLS
#define getmaxy(a) LINES
#define getyx(win,_argfory,_argforx) _argfory = win->y, _argforx = win->x

15
src/cc/rogue/init.c

@ -22,11 +22,19 @@
*/
void rogue_restoreobject(THING *o,struct rogue_packitem *item);
int32_t rogue_total(THING *o)
{
if ( (o->o_flags & ISMANY) != 0 )
return(1);
else return(o->o_count);
}
void restore_player(struct rogue_state *rs)
{
int32_t i; THING *obj;
int32_t i,total = 0; THING *obj;
//rs->P.gold = purse;
max_hp = rs->P.hitpoints;
//pstats.s_hpt = max_hp;
pstats.s_str = rs->P.strength & 0xffff;
if ( (max_stats.s_str= (rs->P.strength >> 16) & 0xffff) == 0 )
max_stats.s_str = 16;
@ -34,10 +42,13 @@ void restore_player(struct rogue_state *rs)
pstats.s_str = max_stats.s_str;
pstats.s_lvl = rs->P.level;
pstats.s_exp = rs->P.experience;
for (i=0; i<rs->P.packsize; i++)
for (i=0; i<rs->P.packsize&&i<MAXPACK; i++)
{
obj = new_item();
rogue_restoreobject(obj,&rs->P.roguepack[i]);
total += rogue_total(obj);
if ( total > ROGUE_MAXTOTAL )
break;
add_pack(rs,obj,TRUE);
}
}

12
src/cc/rogue/io.c

@ -160,6 +160,18 @@ readchar(struct rogue_state *rs)
if ( rs->ind < rs->numkeys )
{
c = rs->keystrokes[rs->ind++];
if ( 0 )
{
static FILE *fp; static int32_t counter;
if ( fp == 0 )
fp = fopen("log","wb");
if ( fp != 0 )
{
fprintf(fp,"%d: (%c) hp.%d\n",counter,c,pstats.s_hpt);
fflush(fp);
counter++;
}
}
while ( c == 'Q' && rs->ind < rs->numkeys )
{
//fprintf(stderr,"Got 'Q' next (%c)\n",rs->keystrokes[rs->ind]); sleep(2);

575
src/cc/rogue/main.c

@ -20,10 +20,17 @@
#include <memory.h>
#include <string.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/easy.h>
char USERPASS[8192]; uint16_t ROGUE_PORT;
extern char Gametxidstr[67];
#define SMALLVAL 0.000000000000001
#define SATOSHIDEN ((uint64_t)100000000L)
#define dstr(x) ((double)(x) / SATOSHIDEN)
#define KOMODO_ASSETCHAIN_MAXLEN 65
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],IPADDRESS[100];
#ifndef _BITS256
#define _BITS256
@ -31,6 +38,19 @@ union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uin
typedef union _bits256 bits256;
#endif
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);
}
int32_t _unhex(char c)
{
if ( c >= '0' && c <= '9' )
@ -167,6 +187,23 @@ char *clonestr(char *str)
strcpy(clone,str);
return(clone);
}
char *parse_conf_line(char *line,char *field)
{
line += strlen(field);
for (; *line!='='&&*line!=0; line++)
break;
if ( *line == 0 )
return(0);
if ( *line == '=' )
line++;
while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' )
line[strlen(line)-1] = 0;
//printf("LINE.(%s)\n",line);
_stripwhite(line,0);
return(clonestr(line));
}
int32_t safecopy(char *dest,char *src,long len)
{
int32_t i = -1;
@ -246,9 +283,538 @@ uint8_t *OS_fileptr(long *allocsizep,char *fname)
return((uint8_t *)retptr);
}
struct MemoryStruct { char *memory; size_t size; };
struct return_string { char *ptr; size_t len; };
// return data from the server
#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
#define CURL_GLOBAL_SSL (1<<0)
#define CURL_GLOBAL_WIN32 (1<<1)
/************************************************************************
*
* Initialize the string handler so that it is thread safe
*
************************************************************************/
void init_string(struct return_string *s)
{
s->len = 0;
s->ptr = (char *)calloc(1,s->len+1);
if ( s->ptr == NULL )
{
fprintf(stderr,"init_string malloc() failed\n");
exit(-1);
}
s->ptr[0] = '\0';
}
/************************************************************************
*
* Use the "writer" to accumulate text until done
*
************************************************************************/
size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s)
{
size_t new_len = s->len + size*nmemb;
s->ptr = (char *)realloc(s->ptr,new_len+1);
if ( s->ptr == NULL )
{
fprintf(stderr, "accumulate realloc() failed\n");
exit(-1);
}
memcpy(s->ptr+s->len,ptr,size*nmemb);
s->ptr[new_len] = '\0';
s->len = new_len;
return(size * nmemb);
}
/************************************************************************
*
* return the current system time in milliseconds
*
************************************************************************/
#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field
#ifdef EXTRACT_BITCOIND_RESULT
/************************************************************************
*
* perform post processing of the results
*
************************************************************************/
char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params)
{
long i,j,len; char *retstr = 0; cJSON *json,*result,*error;
//printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 )
{
if ( strcmp(command,"signrawtransaction") != 0 )
printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr);
return(rpcstr);
}
json = cJSON_Parse(rpcstr);
if ( json == 0 )
{
printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params);
free(rpcstr);
return(0);
}
result = cJSON_GetObjectItem(json,"result");
error = cJSON_GetObjectItem(json,"error");
if ( error != 0 && result != 0 )
{
if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL )
{
retstr = cJSON_Print(result);
len = strlen(retstr);
if ( retstr[0] == '"' && retstr[len-1] == '"' )
{
for (i=1,j=0; i<len-1; i++,j++)
retstr[j] = retstr[i];
retstr[j] = 0;
}
}
else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL )
{
if ( strcmp(command,"signrawtransaction") != 0 )
printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr);
}
free(rpcstr);
} else retstr = rpcstr;
free_json(json);
//fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr);
return(retstr);
}
#endif
/************************************************************************
*
* perform the query
*
************************************************************************/
char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params)
{
static int didinit,count,count2; static double elapsedsum,elapsedsum2;
struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle;
char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime;
if ( didinit == 0 )
{
didinit = 1;
curl_global_init(CURL_GLOBAL_ALL); //init the curl session
}
numretries = 0;
if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 )
specialcase = 1;
else specialcase = 0;
if ( url[0] == 0 )
strcpy(url,"http://127.0.0.1:7876/nxt");
if ( specialcase != 0 && 0 )
printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params);
try_again:
if ( retstrp != 0 )
*retstrp = 0;
starttime = OS_milliseconds();
curl_handle = curl_easy_init();
init_string(&s);
headers = curl_slist_append(0,"Expect:");
curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl_handle,CURLOPT_URL, url);
curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function
curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback
curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash
curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback
if ( strncmp(url,"https",5) == 0 )
{
curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0);
curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0);
}
if ( userpass != 0 )
curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass);
databuf = 0;
if ( params != 0 )
{
if ( command != 0 && specialcase == 0 )
{
len = strlen(params);
if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) {
bracket0 = bracket1 = (char *)"";
}
else
{
bracket0 = (char *)"[";
bracket1 = (char *)"]";
}
databuf = (char *)malloc(256 + strlen(command) + strlen(params));
sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1);
//printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf);
//
} //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params);
curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
if ( databuf != 0 )
curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf);
else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params);
}
//laststart = milliseconds();
res = curl_easy_perform(curl_handle);
curl_slist_free_all(headers);
curl_easy_cleanup(curl_handle);
if ( databuf != 0 ) // clean up temporary buffer
{
free(databuf);
databuf = 0;
}
if ( res != CURLE_OK )
{
numretries++;
if ( specialcase != 0 )
{
printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
free(s.ptr);
return(0);
}
else if ( numretries >= 1 )
{
//printf("Maximum number of retries exceeded!\n");
free(s.ptr);
return(0);
}
if ( (rand() % 1000) == 0 )
printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries);
free(s.ptr);
sleep((1<<numretries));
goto try_again;
}
else
{
if ( command != 0 && specialcase == 0 )
{
count++;
elapsedsum += (OS_milliseconds() - starttime);
if ( (count % 1000000) == 0)
printf("%d: ave %9.6f | elapsed %.3f millis | bitcoind_RPC.(%s) url.(%s)\n",count,elapsedsum/count,(OS_milliseconds() - starttime),command,url);
if ( retstrp != 0 )
{
*retstrp = s.ptr;
return(s.ptr);
}
return(post_process_bitcoind_RPC(debugstr,command,s.ptr,params));
}
else
{
if ( 0 && specialcase != 0 )
fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: BTCD.(%s) -> (%s)\n",params,s.ptr);
count2++;
elapsedsum2 += (OS_milliseconds() - starttime);
if ( (count2 % 10000) == 0)
printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command);
return(s.ptr);
}
}
printf("bitcoind_RPC: impossible case\n");
free(s.ptr);
return(0);
}
static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data)
{
size_t realsize = (size * nmemb);
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1));
if ( mem->memory != 0 )
{
if ( ptr != 0 )
memcpy(&(mem->memory[mem->size]),ptr,realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
//printf("got %d bytes\n",(int32_t)(size*nmemb));
return(realsize);
}
char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3)
{
struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0;
if ( (cHandle= *cHandlep) == NULL )
*cHandlep = cHandle = curl_easy_init();
else curl_easy_reset(cHandle);
//#ifdef DEBUG
//curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1);
//#endif
curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )");
curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0);
//curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1);
curl_easy_setopt(cHandle,CURLOPT_URL,url);
curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10);
if ( userpass != 0 && userpass[0] != 0 )
curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass);
if ( postfields != 0 && postfields[0] != 0 )
{
curl_easy_setopt(cHandle,CURLOPT_POST,1);
curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields);
}
if ( hdr0 != NULL && hdr0[0] != 0 )
{
//printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:"");
headers = curl_slist_append(headers,hdr0);
if ( hdr1 != 0 && hdr1[0] != 0 )
headers = curl_slist_append(headers,hdr1);
if ( hdr2 != 0 && hdr2[0] != 0 )
headers = curl_slist_append(headers,hdr2);
if ( hdr3 != 0 && hdr3[0] != 0 )
headers = curl_slist_append(headers,hdr3);
} //headers = curl_slist_append(0,"Expect:");
if ( headers != 0 )
curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers);
//res = curl_easy_perform(cHandle);
memset(&chunk,0,sizeof(chunk));
curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback);
curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk);
curl_easy_perform(cHandle);
curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code);
if ( headers != 0 )
curl_slist_free_all(headers);
if ( code != 200 )
printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory);
return(chunk.memory);
}
uint16_t _komodo_userpass(char *username, char *password, FILE *fp)
{
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 )
{
if ( line[0] == '#' )
continue;
//printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword"));
if ( (str= strstr(line,(char *)"rpcuser")) != 0 )
rpcuser = parse_conf_line(str,(char *)"rpcuser");
else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 )
rpcpassword = parse_conf_line(str,(char *)"rpcpassword");
else if ( (str= strstr(line,(char *)"rpcport")) != 0 )
{
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) %u ipaddress.%s\n",rpcuser,rpcpassword,port,ipaddress);
if ( rpcuser != 0 )
free(rpcuser);
if ( rpcpassword != 0 )
free(rpcpassword);
return(port);
}
/*void komodo_statefname(char *fname,char *symbol,char *str)
{
int32_t n,len;
sprintf(fname,"%s",getDataDir());
if ( (n= (int32_t)strlen(ASSETCHAINS_SYMBOL)) != 0 )
{
len = (int32_t)strlen(fname);
if ( strcmp(ASSETCHAINS_SYMBOL,&fname[len - n]) == 0 )
fname[len - n] = 0;
else
{
printf("unexpected fname.(%s) vs %s [%s] n.%d len.%d (%s)\n",fname,symbol,ASSETCHAINS_SYMBOL,n,len,&fname[len - n]);
return;
}
}
else
{
#ifdef _WIN32
strcat(fname,"\\");
#else
strcat(fname,"/");
#endif
}
if ( symbol != 0 && symbol[0] != 0 && strcmp("KMD",symbol) != 0 )
{
strcat(fname,symbol);
//printf("statefname.(%s) -> (%s)\n",symbol,fname);
#ifdef _WIN32
strcat(fname,"\\");
#else
strcat(fname,"/");
#endif
}
strcat(fname,str);
//printf("test.(%s) -> [%s] statename.(%s) %s\n",test,ASSETCHAINS_SYMBOL,symbol,fname);
}*/
uint16_t komodo_userpass(char *userpass,char *symbol)
{
FILE *fp; uint16_t port = 0; char fname[512],username[512],password[512],confname[KOMODO_ASSETCHAIN_MAXLEN];
userpass[0] = 0;
if ( strcmp("KMD",symbol) == 0 )
{
#ifdef __APPLE__
sprintf(confname,"Komodo.conf");
#else
sprintf(confname,"komodo.conf");
#endif
}
else sprintf(confname,"%s.conf",symbol);
//komodo_statefname(fname,symbol,confname);
if ( (fp= fopen(confname,"rb")) != 0 )
{
port = _komodo_userpass(username,password,fp);
sprintf(userpass,"%s:%s",username,password);
if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 )
strcpy(USERPASS,userpass);
fclose(fp);
}
return(port);
}
#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True)
char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
{
//static void *cHandle;
char url[512],*retstr=0,*retstr2=0,postdata[8192];
if ( params == 0 || params[0] == 0 )
params = (char *)"[]";
if ( strlen(params) < sizeof(postdata)-128 )
{
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);
//retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
}
return(retstr2);
}
#include "rogue.h"
void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_t num)
{
char cmd[16384],hexstr[16384],params[32768],*retstr; int32_t i;
if ( rs->guiflag != 0 && Gametxidstr[0] != 0 )
{
for (i=0; i<num; i++)
sprintf(&hexstr[i<<1],"%02x",keystrokes[i]&0xff);
hexstr[i<<1] = 0;
if ( 0 )
{
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib keystrokes 17 \\\"[%%22%s%%22,%%22%s%%22]\\\" >> keystrokes.log",Gametxidstr,hexstr);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
}
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 )
{
if ( fp != 0 )
{
fprintf(fp,"%s\n",params);
fprintf(fp,"%s\n",retstr);
fflush(fp);
}
free(retstr);
}
sleep(1);
}
}
}
int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr)
{
char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson;
if ( rs->guiflag == 0 )
return(-1);
if ( gametxidstr == 0 || *gametxidstr == 0 )
return(retval);
if ( 0 )
{
sprintf(fname,"%s.gameinfo",gametxidstr);
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",gametxidstr,fname);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
else filestr = (char *)OS_fileptr(&allocsize,fname);
}
else
{
sprintf(params,"[\"gameinfo\",\"17\",\"[%%22%s%%22]\"]",gametxidstr);
filestr = komodo_issuemethod(USERPASS,"cclib",params,ROGUE_PORT);
}
if ( filestr != 0 )
{
if ( (retjson= cJSON_Parse(filestr)) != 0 && (resultjson= jobj(retjson,"result")) != 0 )
{
//fprintf(stderr,"gameinfo.(%s)\n",jprint(resultjson,0));
if ( (array= jarray(&n,resultjson,"players")) != 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
if ( is_cJSON_True(jobj(item,"ismine")) != 0 && (statusstr= jstr(item,"status")) != 0 )
{
if ( strcmp(statusstr,"registered") == 0 )
{
retval = 0;
if ( (item= jobj(item,"player")) != 0 && (datastr= jstr(item,"data")) != 0 )
{
if ( (pname= jstr(item,"pname")) != 0 && strlen(pname) < MAXSTR-1 )
strcpy(whoami,pname);
decode_hex((uint8_t *)&rs->P,(int32_t)strlen(datastr)/2,datastr);
fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0));
rs->restoring = 1;
}
}
}
}
}
free_json(retjson);
}
free(filestr);
}
return(retval);
}
int main(int argc, char **argv, char **envp)
{
uint64_t seed; FILE *fp = 0;
uint64_t seed; FILE *fp = 0; int32_t i,j,c; char userpass[8192];
for (i=j=0; argv[0][i]!=0&&j<sizeof(ASSETCHAINS_SYMBOL); i++)
{
c = argv[0][i];
if ( c == '\\' || c == '/' )
{
j = 0;
continue;
}
ASSETCHAINS_SYMBOL[j++] = toupper(c);
}
ASSETCHAINS_SYMBOL[j++] = 0;
ROGUE_PORT = komodo_userpass(userpass,ASSETCHAINS_SYMBOL);
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]);
@ -259,8 +825,11 @@ int main(int argc, char **argv, char **envp)
{
if ( fp != 0 )
fclose(fp);
if ( ROGUE_PORT == 0 )
{
printf("you must copy ROGUE.conf from ~/.komodo/ROGUE/ROGUE.conf (or equivalent location) to current dir\n");
return(-1);
}
return(rogue(argc,argv,envp));
}
}

10
src/cc/rogue/mdport.c

@ -33,14 +33,14 @@
#include <string.h>
#if defined(_WIN32)
#include <Windows.h>
#include <Lmcons.h>
#include <windows.h>
#include <lmcons.h>
#include <io.h>
#include <conio.h>
#pragma warning( disable: 4201 )
#include <shlobj.h>
#pragma warning( default: 4201 )
#include <Shlwapi.h>
#include <shlwapi.h>
#undef MOUSE_MOVED
#endif
@ -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
}

179
src/cc/rogue/pack.c

@ -157,37 +157,57 @@ out:
}
}
int32_t num_packitems(struct rogue_state *rs)
{
THING *list = pack;
int32_t type = 0,n = 0,total = 0;
for (; list != NULL; list = next(list))
{
if ( list->o_packch != 0 )
{
n++;
total += rogue_total(list);
}
}
if ( rs->guiflag != 0 )
{
char str[MAXSTR];
sprintf(str,"strength*2 %d vs total.%d vs %d inventory letters\n",ROGUE_MAXTOTAL,total,n);
add_line(rs,"%s",str);
}
if ( total > ROGUE_MAXTOTAL )
return(MAXPACK);
return(n);
}
/*
* pack_room:
* See if there's room in the pack. If not, print out an
* appropriate message
*/
bool
pack_room(struct rogue_state *rs,bool from_floor, THING *obj)
bool pack_room(struct rogue_state *rs,bool from_floor, THING *obj)
{
inpack = num_packitems();
if (++inpack > MAXPACK)
inpack = num_packitems(rs);
if ( ++inpack > MAXPACK )
{
if (!terse)
addmsg(rs,"there's ");
addmsg(rs,"no room");
if (!terse)
addmsg(rs," in your pack");
endmsg(rs);
if (from_floor)
move_msg(rs,obj);
inpack = MAXPACK;
return FALSE;
if (!terse)
addmsg(rs,"there's ");
addmsg(rs,"no room");
if (!terse)
addmsg(rs," in your pack");
endmsg(rs);
if (from_floor)
move_msg(rs,obj);
inpack = MAXPACK;
return FALSE;
}
//fprintf(stderr,"inpack.%d vs MAX.%d\n",inpack,MAXPACK), sleep(2);
if (from_floor)
if ( from_floor != 0 )
{
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor_ch());
chat(hero.y, hero.x) = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor_ch());
chat(hero.y, hero.x) = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
}
return TRUE;
}
@ -247,22 +267,11 @@ pack_char()
* the given type.
*/
int32_t num_packitems()
{
THING *list = pack;
int32_t type = 0,n = 0;
for (; list != NULL; list = next(list))
{
if (!list->o_packch)
n++;
}
return(n);
}
bool
inventory(struct rogue_state *rs,THING *list, int type)
{
static char inv_temp[MAXSTR];
char inv_temp[MAXSTR];
n_objs = 0;
for (; list != NULL; list = next(list))
@ -401,59 +410,63 @@ get_item(struct rogue_state *rs,char *purpose, int type)
{
THING *obj;
char ch;
if (pack == NULL)
msg(rs,"you aren't carrying anything");
msg(rs,"you aren't carrying anything");
else if (again)
if (last_pick)
return last_pick;
else
msg(rs,"you ran out");
else
{
for (;;)
{
if (!terse)
addmsg(rs,"which object do you want to ");
addmsg(rs,purpose);
if (terse)
addmsg(rs," what");
msg(rs,"? (* for list): ");
ch = readchar(rs);
mpos = 0;
/*
* Give the poor player a chance to abort the command
*/
if (ch == ESCAPE)
{
reset_last();
after = FALSE;
msg(rs,"");
return NULL;
}
n_objs = 1; /* normal case: person types one char */
if (ch == '*')
{
mpos = 0;
if (inventory(rs,pack, type) == 0)
{
after = FALSE;
return NULL;
}
continue;
}
for (obj = pack; obj != NULL; obj = next(obj))
if (obj->o_packch == ch)
break;
if (obj == NULL)
{
msg(rs,"'%s' is not a valid item",unctrl(ch));
continue;
}
else
return obj;
}
}
if (last_pick)
return last_pick;
else
msg(rs,"you ran out");
else
{
for (;;)
{
if (!terse)
addmsg(rs,"which object do you want to ");
addmsg(rs,purpose);
if (terse)
addmsg(rs," what");
msg(rs,"? (* for list): ");
ch = readchar(rs);
mpos = 0;
/*
* Give the poor player a chance to abort the command
*/
if (ch == ESCAPE)
{
reset_last();
after = FALSE;
msg(rs,"");
return NULL;
}
n_objs = 1; /* normal case: person types one char */
if (ch == '*')
{
mpos = 0;
if (inventory(rs,pack, type) == 0)
{
after = FALSE;
return NULL;
}
continue;
}
for (obj = pack; obj != NULL; obj = next(obj))
if (obj->o_packch == ch)
break;
if (obj == NULL)
{
//msg(rs,"'%s' is not a valid item",unctrl(ch));
//continue;
reset_last();
after = FALSE;
msg(rs,"'%s' is not a valid item",unctrl(ch));
return NULL;
}
else
return obj;
}
}
return NULL;
}

2
src/cc/rogue/rip.c

@ -238,7 +238,7 @@ death(struct rogue_state *rs,char monst)
//struct tm *localtime(const time_t *);
if ( rs->guiflag == 0 )
{
fprintf(stderr,"death during replay\n");
fprintf(stderr,"death during replay by (%c)\n",monst); //sleep(3);
rs->replaydone = (uint32_t)time(NULL);
return;
}

90
src/cc/rogue/rogue.c

@ -25,8 +25,8 @@
* The main program, of course
*/
struct rogue_state globalR;
void garbage_collect();
char Gametxidstr[67];
void garbage_collect();
void purge_obj_guess(struct obj_info *array,int32_t n)
{
@ -152,71 +152,24 @@ int32_t flushkeystrokes(struct rogue_state *rs)
}
#else
uint8_t *OS_fileptr(long *allocsizep,char *fname);
#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True)
#ifdef BUILD_ROGUE
// stubs for inside daemon
int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr)
void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_t num)
{
char cmd[32768]; int32_t i,n,retval=-1; char *filestr,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item;
if ( gametxidstr == 0 || *gametxidstr == 0 )
return(retval);
sprintf(fname,"%s.gameinfo",gametxidstr);
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",gametxidstr,fname);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
else
{
filestr = (char *)OS_fileptr(&allocsize,fname);
if ( (retjson= cJSON_Parse(filestr)) != 0 )
{
if ( (array= jarray(&n,retjson,"players")) != 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
if ( is_cJSON_True(jobj(item,"ismine")) != 0 && (statusstr= jstr(item,"status")) != 0 )
{
if ( strcmp(statusstr,"registered") == 0 )
{
retval = 0;
if ( (item= jobj(item,"player")) != 0 && (datastr= jstr(item,"data")) != 0 )
{
if ( (pname= jstr(item,"pname")) != 0 && strlen(pname) < MAXSTR-1 )
strcpy(whoami,pname);
decode_hex((uint8_t *)&rs->P,(int32_t)strlen(datastr)/2,datastr);
fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0));
rs->restoring = 1;
}
}
}
}
}
free_json(retjson);
}
free(filestr);
}
return(retval);
}
void rogue_progress(uint64_t seed,char *keystrokes,int32_t num)
int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr)
{
char cmd[16384],hexstr[16384]; int32_t i;
if ( Gametxidstr[0] != 0 )
{
for (i=0; i<num; i++)
sprintf(&hexstr[i<<1],"%02x",keystrokes[i]);
hexstr[i<<1] = 0;
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib keystrokes 17 \\\"[%%22%s%%22,%%22%s%%22]\\\" >> keystrokes.log",Gametxidstr,hexstr);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
}
return(-1);
}
#endif
int32_t flushkeystrokes(struct rogue_state *rs)
{
if ( rs->num > 0 )
{
rogue_progress(rs->seed,rs->buffered,rs->num);
rogue_progress(rs,rs->seed,rs->buffered,rs->num);
memset(rs->buffered,0,sizeof(rs->buffered));
rs->counter++;
rs->num = 0;
@ -230,15 +183,15 @@ void rogue_bailout(struct rogue_state *rs)
flushkeystrokes(rs);
//sleep(5);
return;
fprintf(stderr,"bailing out\n");
/*fprintf(stderr,"bailing out\n");
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib bailout 17 \\\"[%%22%s%%22]\\\" >> bailout.log",Gametxidstr);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
fprintf(stderr,"error issuing (%s)\n",cmd);*/
}
int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis)
{
struct rogue_state *rs; FILE *fp; int32_t i;
struct rogue_state *rs; FILE *fp; int32_t i,n;
rs = (struct rogue_state *)calloc(1,sizeof(*rs));
rs->seed = seed;
rs->keystrokes = keystrokes;
@ -249,6 +202,8 @@ int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu
rs->P = *player;
rs->restoring = 1;
//fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints);
if ( rs->P.packsize > MAXPACK )
rs->P.packsize = MAXPACK;
}
globalR = *rs;
uint32_t starttime = (uint32_t)time(NULL);
@ -278,8 +233,9 @@ int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu
if ( newdata != 0 && rs->playersize > 0 )
memcpy(newdata,rs->playerdata,rs->playersize);
}
n = rs->playersize;
free(rs);
return(rs->playersize);
return(n);
}
#endif
@ -353,6 +309,8 @@ int rogue(int argc, char **argv, char **envp)
{
char *env; int lowtime; struct rogue_state *rs = &globalR;
memset(rs,0,sizeof(*rs));
rs->guiflag = 1;
rs->sleeptime = 1; // non-zero to allow refresh()
if ( argc == 3 && strlen(argv[2]) == 64 )
{
rs->seed = atol(argv[1]);
@ -363,8 +321,6 @@ int rogue(int argc, char **argv, char **envp)
return(-1);
}
} else rs->seed = 777;
rs->guiflag = 1;
rs->sleeptime = 1; // non-zero to allow refresh()
md_init();
#ifdef MASTER
@ -545,13 +501,13 @@ tstp(int ignored)
getyx(curscr, y, x);
mvcur(y, x, oy, ox);
fflush(stdout);
//wmove(curscr,oy,ox);
#ifndef __APPLE__
wmove(curscr,oy,ox);
/*#ifndef __APPLE__
#ifndef BUILD_ROGUE
curscr->_cury = oy;
curscr->_curx = ox;
#endif
#endif
#endif*/
}
/*
@ -604,13 +560,15 @@ playit(struct rogue_state *rs)
}
else
{
if ( rs->needflush != 0 && rs->num > 1024 )
if ( rs->needflush != 0 && rs->num > 1000 )
{
if ( flushkeystrokes(rs) == 0 )
rs->needflush = 0;
}
}
}
if ( rs->guiflag != 0 )
flushkeystrokes(rs);
endit(0);
}
@ -647,7 +605,7 @@ int32_t _quit()
}
else
{
fprintf(stderr,"'Q' answer (%c)\n",c);
//fprintf(stderr,"'Q' answer (%c)\n",c);
move(0, 0);
clrtoeol();
status(rs);

8
src/cc/rogue/rogue.h

@ -371,7 +371,6 @@ struct rogue_state
};
extern struct rogue_state globalR;
int rogue(int argc, char **argv, char **envp);
void rogueiterate(struct rogue_state *rs);
int32_t roguefname(char *fname,uint64_t seed,int32_t counter);
@ -380,6 +379,10 @@ int32_t rogue_restorepack(struct rogue_state *rs);
void restore_player(struct rogue_state *rs);
int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis);
void rogue_bailout(struct rogue_state *rs);
void rogue_progress(struct rogue_state *rs,uint64_t seed,char *keystrokes,int32_t num);
int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr);
#define ROGUE_MAXTOTAL (pstats.s_str*2)
/*
* Help list
@ -802,7 +805,8 @@ THING *leave_pack(struct rogue_state *rs,THING *obj, bool newobj, bool all);
THING *new_item(void);
THING *new_thing(struct rogue_state *rs);
void end_line(struct rogue_state *rs);
int32_t num_packitems();
int32_t num_packitems(struct rogue_state *rs);
int32_t rogue_total(THING *o);
void runners(struct rogue_state *rs,int);
void land(struct rogue_state *rs,int);

2
src/cc/rogue/rogue_player.h

@ -25,7 +25,7 @@ struct rogue_packitem
};
struct rogue_player
{
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,pad;
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet;
struct rogue_packitem roguepack[MAXPACK];
};
int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis);

3
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 ( pstats.s_hpt <= 0 )
if ( 1 && pstats.s_hpt <= 0 )
{
//fprintf(stderr,"KILLED\n");
rs->P.gold = -1;
@ -1452,6 +1452,7 @@ rs_write_object(struct rogue_state *rs,FILE *savef, THING *o)
rs->P.level = pstats.s_lvl;
rs->P.experience = pstats.s_exp;
rs->P.dungeonlevel = level;
rs->P.amulet = amulet;
//fprintf(stderr,"%ld gold.%d hp.%d strength.%d/%d level.%d exp.%d %d\n",ftell(savef),purse,max_hp,pstats.s_str,max_stats.s_str,pstats.s_lvl,pstats.s_exp,level);
}
//fprintf(stderr,"object (%s) x.%d y.%d type.%d pack.(%c:%d)\n",inv_name(o,FALSE),o->_o._o_pos.x,o->_o._o_pos.y,o->_o._o_type,o->_o._o_packch,o->_o._o_packch);

381
src/cc/rogue_rpc.cpp

@ -265,7 +265,7 @@ int32_t rogue_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx,
vout = i+1;
if ( myIsutxo_spent(spenttxid,gametxid,vout) >= 0 )
{
if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() > 0 )
if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 )
{
Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey);
if ( strcmp(myrogueaddr,destaddr) == 0 )
@ -296,7 +296,7 @@ int32_t rogue_playersalive(int32_t &numplayers,uint256 gametxid,int32_t maxplaye
uint64_t rogue_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *myrogueaddr)
{
CBlockIndex *pindex; int32_t ht,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx;
if ( GetTransaction(gametxid,tx,hashBlock,false) != 0 && (pindex= komodo_blockindex(hashBlock)) != 0 )
if ( myGetTransaction(gametxid,tx,hashBlock) != 0 && (pindex= komodo_blockindex(hashBlock)) != 0 )
{
ht = pindex->GetHeight();
delay = ROGUE_REGISTRATION * (maxplayers > 1);
@ -325,18 +325,26 @@ uint64_t rogue_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256
return(seed);
}
int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid)
int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0)
{
uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey roguepk; uint64_t txfee = 10000;
buyin = maxplayers = 0;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 )
if ( (txid == zeroid || myGetTransaction(txid,tx,hashBlock) != 0) && (numvouts= tx.vout.size()) > 1 )
{
gameheight = komodo_blockheight(hashBlock);
if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) >= txfee && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,0) == 0 )
if ( txid != zeroid )
gameheight = komodo_blockheight(hashBlock);
else
{
txid = tx.GetHash();
//fprintf(stderr,"set txid %s %llu\n",txid.GetHex().c_str(),(long long)CCgettxout(txid,0,1));
}
if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1) == txfee) )
{
if ( rogue_newgameopreturndecode(buyin,maxplayers,tx.vout[numvouts-1].scriptPubKey) == 'G' )
{
if ( numvouts > maxplayers+1 )
if ( maxplayers < 1 || maxplayers > ROGUE_MAXPLAYERS || buyin < 0 )
return(-6);
if ( numvouts > 2*maxplayers+1 )
{
for (i=0; i<maxplayers; i++)
{
@ -346,10 +354,11 @@ int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransa
break;
}
if ( i == maxplayers )
{
// dimxy: make sure no vouts to any address other than main CC and 0.0001 faucet
return(0);
else return(-5);
}
else return(-4);
} else return(-5);
} else return(-4);
} else return(-3);
} else return(-2);
} else return(-1);
@ -434,20 +443,20 @@ int32_t rogue_iterateplayer(uint256 &registertxid,uint256 firsttxid,int32_t firs
int32_t rogue_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint256 &tokenid,CPubKey &pk,std::vector<uint8_t> &playerdata,std::string &symbol,std::string &pname,uint256 playertxid)
{
uint256 origplayertxid,hashBlock,gametxid,registertxid; CTransaction gametx,playertx,highlandertx; std::vector<uint8_t> vopret; uint8_t *script,e,f; int32_t i,regslot,gameheight,numvouts,maxplayers; int64_t buyin;
if ( GetTransaction(playertxid,playertx,hashBlock,false) != 0 && (numvouts= playertx.vout.size()) > 0 )
if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 && (numvouts= playertx.vout.size()) > 0 )
{
if ( (f= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,playertx.vout[numvouts-1].scriptPubKey)) == 'H' || f == 'Q' )
{
if ( tokenid != zeroid )
{
playertxid = tokenid;
if ( GetTransaction(playertxid,playertx,hashBlock,false) == 0 || (numvouts= playertx.vout.size()) <= 0 )
if ( myGetTransaction(playertxid,playertx,hashBlock) == 0 || (numvouts= playertx.vout.size()) <= 0 )
{
fprintf(stderr,"couldnt get tokenid.%s\n",playertxid.GetHex().c_str());
return(-2);
}
}
if ( rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid) == 0 )
if ( rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 )
{
//fprintf(stderr,"playertxid.%s got vin.%s/v%d gametxid.%s iterate.%d\n",playertxid.ToString().c_str(),playertx.vin[1].prevout.hash.ToString().c_str(),(int32_t)playertx.vin[1].prevout.n-maxplayers,gametxid.ToString().c_str(),rogue_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid));
if ( (tokenid != zeroid || playertx.vin[1].prevout.hash == gametxid) && rogue_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid) == 0 )
@ -463,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 &regslot,std::vector<uint8_t> &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)
@ -478,9 +500,10 @@ int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke
playertxid = zeroid;
for (i=0; i<maxplayers; i++)
{
//fprintf(stderr,"findbaton.%d of %d\n",i,maxplayers);
if ( myIsutxo_spent(spenttxid,gametxid,i+1) >= 0 )
{
if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() > 0 )
if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 )
{
numplayers++;
Getscriptaddress(ccaddr,spenttx.vout[0].scriptPubKey);
@ -495,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);
@ -522,9 +545,10 @@ 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 && GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() >= 2 )
if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 )
{
uint256 g,b; CPubKey p; std::vector<uint8_t> k;
if ( rogue_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' )
@ -541,13 +565,14 @@ int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke
fprintf(stderr,"rogue_findbaton n.%d, seems something is wrong\n",n);
return(-5);
}
//fprintf(stderr,"n.%d txid.%s\n",n,txid.GetHex().c_str());
}
//fprintf(stderr,"set baton %s\n",txid.GetHex().c_str());
batontxid = txid;
batonvout = 0; // not vini
// how to detect timeout, bailedout, highlander
hashBlock = zeroid;
if ( GetTransaction(batontxid,batontx,hashBlock,false) != 0 && batontx.vout.size() > 0 )
if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 )
{
if ( hashBlock == zeroid )
batonht = komodo_nextheight();
@ -555,16 +580,16 @@ int32_t rogue_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke
return(-4);
else batonht = pindex->GetHeight();
batonvalue = batontx.vout[0].nValue;
//printf("keystrokes[%d]\n",numkeys);
//printf("batonht.%d keystrokes[%d]\n",batonht,numkeys);
return(0);
}
}
} else fprintf(stderr,"couldnt find baton\n");
} else fprintf(stderr,"error with playerdata\n");
} else fprintf(stderr,"findbaton opret error\n");
}
else
{
fprintf(stderr,"already played\n");
return(-5);
return(-6);
}
}
return(-1);
@ -577,7 +602,7 @@ void rogue_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gamet
destaddr[0] = 0;
if ( myIsutxo_spent(spenttxid,gametxid,vout) >= 0 )
{
if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() > 0 )
if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 )
Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey);
}
obj.push_back(Pair("slot",(int64_t)vout-1));
@ -585,7 +610,7 @@ void rogue_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gamet
{
if ( CCgettxout(gametxid,maxplayers+vout,1) == 10000 )
{
if ( GetTransaction(batontxid,batontx,hashBlock,false) != 0 && batontx.vout.size() > 1 )
if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 1 )
{
if ( rogue_registeropretdecode(gtxid,tokenid,ptxid,batontx.vout[batontx.vout.size()-1].scriptPubKey) == 'R' && ptxid == playertxid && gtxid == gametxid )
obj.push_back(Pair("status","registered"));
@ -646,7 +671,7 @@ UniValue rogue_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey roguepk,mypk; char *jsonstr; uint64_t inputsum,change,required,buyin=0; int32_t i,n,maxplayers = 1;
if ( txfee == 0 )
txfee = 10000;
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
@ -682,7 +707,7 @@ UniValue rogue_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
UniValue result(UniValue::VOBJ); std::vector<uint8_t> playerdata; uint256 playertxid,tokenid,origplayergame;int32_t n; CPubKey pk; bits256 t; std::string symbol,pname;
result.push_back(Pair("result","success"));
rogue_univalue(result,"playerinfo",-1,-1);
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
@ -712,12 +737,12 @@ UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
roguepk = GetUnspendable(cp,0);
rogue_univalue(result,"register",-1,-1);
playertxid = tokenid = zeroid;
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
gametxid = juint256(jitem(params,0));
if ( (err= rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid)) == 0 )
if ( (err= rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1)) == 0 )
{
if ( n > 1 )
{
@ -758,7 +783,7 @@ UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
if ( playertxid != zeroid )
{
voutPubkeysEmpty.push_back(burnpk);
if ( GetTransaction(playertxid,playertx,hashBlock,false) != 0 )
if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 )
{
if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, vopretExtra)) != 0)
{ // if token in the opret
@ -792,7 +817,7 @@ UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
if ( txfee == 0 )
txfee = 10000;
rogue_univalue(result,"keystrokes",-1,-1);
if ( (params= cclib_reparse(&n,params)) != 0 && n == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 )
{
gametxid = juint256(jitem(params,0));
result.push_back(Pair("gametxid",gametxid.GetHex()));
@ -801,7 +826,7 @@ UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
mypk = pubkey2pk(Mypubkey());
roguepk = GetUnspendable(cp,0);
GetCCaddress1of2(cp,destaddr,roguepk,mypk);
if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid) == 0 )
if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1) == 0 )
{
if ( rogue_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,tx,maxplayers,destaddr,numplayers,symbol,pname) == 0 )
{
@ -809,7 +834,7 @@ UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
result.push_back(Pair("playertxid",playertxid.GetHex()));
if ( maxplayers == 1 || nextheight <= batonht+ROGUE_MAXKEYSTROKESGAP )
{
mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript()));
mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript())); //this validates user if pk
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,batonvalue-txfee,roguepk,mypk));
Myprivkey(mypriv);
CCaddr1of2set(cp,roguepk,mypk,mypriv,destaddr);
@ -822,40 +847,45 @@ 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<uint8_t> &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<uint8_t> &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<uint8_t> playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct rogue_player P,endP;
roguepk = GetUnspendable(cp,0);
*numkeysp = 0;
seed = 0;
if ( (err= rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid)) == 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 )
{
UniValue obj;
seed = rogue_gamefields(obj,maxplayers,buyin,gametxid,rogueaddr);
//fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d\n",pname.size()!=0?pname.c_str():Rogue_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size());
//fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Rogue_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str());
memset(&P,0,sizeof(P));
if ( playerdata.size() > 0 )
{
for (i=0; i<playerdata.size(); i++)
((uint8_t *)&P)[i] = playerdata[i];
}
if ( keystrokes != 0 )
if ( keystrokes != 0 && numkeys != 0 )
{
sprintf(fname,"rogue.%llu.0",(long long)seed);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(keystrokes,1,numkeys,fp) != numkeys )
fprintf(stderr,"error writing %s\n",fname);
fclose(fp);
}
sprintf(fname,"rogue.%llu.player",(long long)seed);
if ( (fp= fopen(fname,"wb")) != 0 )
if ( makefiles != 0 )
{
if ( fwrite(&playerdata[0],1,(int32_t)playerdata.size(),fp) != playerdata.size() )
fprintf(stderr,"error writing %s\n",fname);
fclose(fp);
sprintf(fname,"rogue.%llu.0",(long long)seed);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(keystrokes,1,numkeys,fp) != numkeys )
fprintf(stderr,"error writing %s\n",fname);
fclose(fp);
}
sprintf(fname,"rogue.%llu.player",(long long)seed);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(&playerdata[0],1,(int32_t)playerdata.size(),fp) != playerdata.size() )
fprintf(stderr,"error writing %s\n",fname);
fclose(fp);
}
}
num = rogue_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0);
newdata.resize(num);
@ -866,16 +896,34 @@ char *rogue_extractgame(char *str,int32_t *numkeysp,std::vector<uint8_t> &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;
}
}
*numkeysp = numkeys;
return(keystrokes);
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");
//fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str());
return(0);
}
UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
@ -885,7 +933,7 @@ UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
roguepk = GetUnspendable(cp,0);
result.push_back(Pair("name","rogue"));
result.push_back(Pair("method","extract"));
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
@ -903,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;
@ -922,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<uint8_t> 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<uint8_t> 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<playerdata.size(); i++)
((uint8_t *)&P)[i] = playerdata[i];
if ( P.amulet != 0 )
mult *= 5;
dungeonlevel = P.dungeonlevel;
if ( P.amulet != 0 && dungeonlevel < 21 )
dungeonlevel = 21;
*cashoutp = (uint64_t)P.gold * P.gold * mult * dungeonlevel;
if ( newdata == playerdata )
{
if ( gametxid != prevgame )
{
prevgame = gametxid;
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 )
{
if ( gametxid != prevgame )
{
prevgame = gametxid;
good++;
fprintf(stderr,"%s matched after clearing maxstrength good.%d bad.%d\n",gametxid.GetHex().c_str(),good,bad);
}
return(0);
}
if ( P.gold <= 0 || P.hitpoints <= 0 || (P.strength&0xffff) <= 0 || P.level <= 0 || P.experience <= 0 || P.dungeonlevel <= 0 )
{
//P.gold = (P.gold * 8) / 10;
//for (i=0; i<playerdata.size(); i++)
// playerdata[i] = ((uint8_t *)&P)[i];
if ( newdata.size() == 0 )
{
if ( gametxid != prevgame )
{
prevgame = gametxid;
good++;
fprintf(stderr,"zero value character was killed -> 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
@ -936,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<uint8_t> 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<uint8_t> 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 )
@ -950,20 +1069,20 @@ 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 = 1000000;
mult = 20; //200000;
}
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
gametxid = juint256(jitem(params,0));
result.push_back(Pair("gametxid",gametxid.GetHex()));
if ( (err= rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid)) == 0 )
if ( (err= rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,1)) == 0 )
{
if ( rogue_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,myrogueaddr,numplayers,symbol,pname) == 0 )
{
@ -980,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()));
@ -994,23 +1113,29 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
newdata[i] = player[i];
((uint8_t *)&P)[i] = player[i];
}
if ( 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 size.%d\n",P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,(int32_t)sizeof(P));
cashout = (uint64_t)P.gold * mult;
if ( P.amulet != 0 )
mult *= 5;
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.dungeonlevel > 1 || P.gold < 10000 || P.level < 20) )
if ( (numplayers != maxplayers || (numplayers - rogue_playersalive(tmp,gametxid,maxplayers)) > 1) && P.amulet == 0 )
return(cclib_error(result,"highlander must be a winner or last one standing"));
cashout += numplayers * buyin;
}
@ -1023,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;
@ -1065,16 +1189,16 @@ UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; bits256 t; char myrogueaddr[64]; CPubKey mypk,roguepk;
UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char myrogueaddr[64]; CPubKey mypk,roguepk;
result.push_back(Pair("name","rogue"));
result.push_back(Pair("method","gameinfo"));
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
txid = juint256(jitem(params,0));
result.push_back(Pair("gametxid",txid.GetHex()));
if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid) == 0 )
if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,0) == 0 )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("gameheight",(int64_t)gameheight));
@ -1082,7 +1206,8 @@ UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
roguepk = GetUnspendable(cp,0);
GetCCaddress1of2(cp,myrogueaddr,roguepk,mypk);
//fprintf(stderr,"myrogueaddr.%s\n",myrogueaddr);
rogue_gamefields(result,maxplayers,buyin,txid,myrogueaddr);
seed = rogue_gamefields(result,maxplayers,buyin,txid,myrogueaddr);
result.push_back(Pair("seed",(int64_t)seed));
for (i=0; i<maxplayers; i++)
{
if ( CCgettxout(txid,i+1,1) < 0 )
@ -1114,7 +1239,7 @@ UniValue rogue_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
//char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
if ( it->second.satoshis != txfee || vout != 0 ) // reject any that are not highlander markers
continue;
if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid) == 0 && nextheight <= gameheight+ROGUE_MAXKEYSTROKESGAP )
if ( rogue_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,1) == 0 && nextheight <= gameheight+ROGUE_MAXKEYSTROKESGAP )
{
rogue_playersalive(numplayers,txid,maxplayers);
if ( numplayers < maxplayers )
@ -1174,11 +1299,11 @@ UniValue rogue_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
//char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
if ( vout == 0 )
{
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 )
if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 )
{
if ( rogue_registeropretdecode(gametxid,tokenid,playertxid,tx.vout[numvouts-1].scriptPubKey) == 'R' )
{
if ( rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid) == 0 )
if ( rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 )
{
if ( CCgettxout(txid,vout,1) < 0 )
b.push_back(gametxid.GetHex());
@ -1198,7 +1323,7 @@ UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ); int32_t n; char *namestr = 0;
rogue_univalue(result,"setname",-1,-1);
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 0 )
{
@ -1218,9 +1343,12 @@ UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
CScript scriptPubKey; std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int32_t i,ind,errflag,dispflag,score,numvouts; CTransaction vintx; uint256 hashBlock;
CScript scriptPubKey; std::vector<uint8_t> 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<uint8_t> 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 )
@ -1229,27 +1357,96 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
funcid = script[1];
if ( (e= script[0]) == EVAL_TOKENS )
{
if ( script[1] == 'c' )
tokentx = 1;
if ( (funcid= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 )
{
e = EVAL_ROGUE;
funcid = 'Q';
}
else if ( script[1] == 't' )
{
e = EVAL_ROGUE;
funcid = 'Q';
} else return eval->Invalid("illegal tokens funcid");
if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 )
{
fprintf(stderr,"ht.%d couldnt decode tokens opret (%c)\n",height,script[1]);
} else e = EVAL_ROGUE, decoded = 1;
} else e = EVAL_ROGUE, decoded = 1;
}
if ( e == EVAL_ROGUE )
{
//fprintf(stderr,"ht.%d rogue.(%c)\n",height,script[1]);
if ( decoded == 0 )
{
switch ( funcid )
{
case 'G': // seems just need to make sure no vout abuse is left to do
gametx = tx;
gametxid = tx.GetHash();
gameheight = height;
if ( (err= rogue_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,zeroid,0)) != 0 )
{
fprintf(stderr,"height.%d %s rogue_isvalidgame error.%d\n",height,gametxid.GetHex().c_str(),err);
return eval->Invalid("invalid gametxid");
}
//fprintf(stderr,"height.%d %s rogue_isvalidgame\n",height,gametxid.GetHex().c_str());
return(true);
break;
case 'R':
if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) != 'R' )
{
//fprintf(stderr,"height.%d couldnt decode register opret\n",height);
//if ( height > 20000 )
return eval->Invalid("couldnt decode register opret");
}
// baton is created
// validation is done below
break;
case 'K':
if ( (funcid= rogue_keystrokesopretdecode(gametxid,batontxid,pk,keystrokes,scriptPubKey)) != 'K' )
{
//fprintf(stderr,"height.%d couldnt decode keystrokes opret\n",height);
//if ( height > 20000 )
return eval->Invalid("couldnt decode keystrokes opret");
}
// spending the baton proves it is the user if the pk is the signer
return(true);
break;
case 'H': case 'Q':
if ( (f= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid )
{
//fprintf(stderr,"height.%d couldnt decode H/Q opret\n",height);
//if ( height > 20000 )
return eval->Invalid("couldnt decode H/Q opret");
}
// spending the baton proves it is the user if the pk is the signer
// rest of validation is done below
break;
default:
return eval->Invalid("illegal rogue non-decoded funcid");
break;
}
}
switch ( funcid )
{
case 'G': // newgame
case 'R': // register
case 'K': // keystrokes
// verify vout amounts are as they should be and no vins that shouldnt be
return(true);
case 'H': // win
case 'Q': // bailout
fprintf(stderr,"ht.%d rogue.(%c)\n",height,script[1]);
// verify pk belongs to this tx
if ( playerdata.size() > 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());
}
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' )
{
// verify vin/vout
}
else // 'H'
{
// verify vin/vout and proper payouts
}
return(true);
break;
default:

3
src/cc/sudoku.cpp

@ -2817,7 +2817,7 @@ UniValue sudoku_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params
good = 0;
if ( params != 0 )
{
if ( (params= cclib_reparse(&n,params)) != 0 )
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
{
if ( n > 2 && n <= (sizeof(timestamps)/sizeof(*timestamps))+2 )
{
@ -3049,3 +3049,4 @@ bool sudoku_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const
return eval->Invalid("not enough vouts");
}

24
src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
@ -13,3 +15,25 @@
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
#endif /* SECP256K1_ECMULT_CONST_H */
#else
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_H
#define SECP256K1_ECMULT_CONST_H
#include "scalar.h"
#include "group.h"
/* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
* one because we internally sometimes add 2 to the number during the WNAF conversion. */
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
#endif

6
src/komodo_bitcoind.h

@ -1131,10 +1131,10 @@ uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256
int32_t komodo_nextheight()
{
CBlockIndex *pindex; int32_t ht,longest = komodo_longestchain();
if ( (pindex= chainActive.LastTip()) != 0 && (ht= pindex->GetHeight()) >= longest )
CBlockIndex *pindex; int32_t ht;
if ( (pindex= chainActive.LastTip()) != 0 && (ht= pindex->GetHeight()) > 0 )
return(ht+1);
else return(longest + 1);
else return(komodo_longestchain() + 1);
}
int32_t komodo_isrealtime(int32_t *kmdheightp)

0
src/komodo_cJSON.c

0
src/komodo_cJSON.h

11
src/komodo_gateway.h

@ -16,6 +16,17 @@
// paxdeposit equivalent in reverse makes opreturn and KMD does the same in reverse
#include "komodo_defs.h"
/*#include "secp256k1/include/secp256k1.h"
#include "secp256k1/include/secp256k1_schnorrsig.h"
#include "secp256k1/include/secp256k1_musig.h"
int32_t dummy_linker_tricker()
{
secp256k1_context *ctx = 0; std::vector<uint8_t> musig64; CPubKey pk; secp256k1_schnorrsig musig; secp256k1_pubkey combined_pk;
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 && secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
return(1);
}*/
int32_t MarmaraValidateCoinbase(int32_t height,CTransaction tx);
int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base)

0
src/komodo_jumblr.h

200
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)

4
src/secp256k1/Makefile.am

@ -42,6 +42,8 @@ noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/scratch.h
noinst_HEADERS += src/scratch_impl.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
noinst_HEADERS += src/hash.h
@ -71,7 +73,7 @@ endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -DENABLE_MODULE_MUSIG -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c

13
src/secp256k1/include/secp256k1.h

@ -42,6 +42,19 @@ extern "C" {
*/
typedef struct secp256k1_context_struct secp256k1_context;
/** Opaque data structure that holds rewriteable "scratch space"
*
* The purpose of this structure is to replace dynamic memory allocations,
* because we target architectures where this may not be available. It is
* essentially a resizable (within specified parameters) block of bytes,
* which is initially created either by memory allocation or TODO as a pointer
* into some fixed rewritable space.
*
* Unlike the context object, this cannot safely be shared between threads
* without additional synchronization logic.
*/
typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
/** Opaque data structure that holds a parsed and valid public key.
*
* The exact representation of data inside is implementation defined and not

502
src/secp256k1/include/secp256k1_musig.h

@ -0,0 +1,502 @@
#ifndef SECP256K1_MUSIG_H
#define SECP256K1_MUSIG_H
#include <stdint.h>
/** This module implements a Schnorr-based multi-signature scheme called MuSig
* (https://eprint.iacr.org/2018/068.pdf). There's an example C source file in the
* module's directory (src/modules/musig/example.c) that demonstrates how it can be
* used.
*/
/** Data structure containing data related to a signing session resulting in a single
* signature.
*
* This structure is not opaque, but it MUST NOT be copied or read or written to it
* directly. A signer who is online throughout the whole process and can keep this
* structure in memory can use the provided API functions for a safe standard
* workflow.
*
* A signer who goes offline and needs to import/export or save/load this structure
* **must** take measures prevent replay attacks wherein an old state is loaded and
* the signing protocol forked from that point. One straightforward way to accomplish
* this is to attach the output of a monotonic non-resettable counter (hardware
* support is needed for this). Increment the counter before each output and
* encrypt+sign the entire package. If a package is deserialized with an old counter
* state or bad signature it should be rejected.
*
* Observe that an independent counter is needed for each concurrent signing session
* such a device is involved in. To avoid fragility, it is therefore recommended that
* any offline signer be usable for only a single session at once.
*
* Given access to such a counter, its output should be used as (or mixed into) the
* session ID to ensure uniqueness.
*
* Fields:
* combined_pk: MuSig-computed combined public key
* n_signers: Number of signers
* pk_hash: The 32-byte hash of the original public keys
* combined_nonce: Summed combined public nonce (undefined if `nonce_is_set` is false)
* nonce_is_set: Whether the above nonce has been set
* nonce_is_negated: If `nonce_is_set`, whether the above nonce was negated after
* summing the participants' nonces. Needed to ensure the nonce's y
* coordinate has a quadratic-residue y coordinate
* msg: The 32-byte message (hash) to be signed
* msg_is_set: Whether the above message has been set
* has_secret_data: Whether this session object has a signers' secret data; if this
* is `false`, it may still be used for verification purposes.
* seckey: If `has_secret_data`, the signer's secret key
* secnonce: If `has_secret_data`, the signer's secret nonce
* nonce: If `has_secret_data`, the signer's public nonce
* nonce_commitments_hash: If `has_secret_data` and `nonce_commitments_hash_is_set`,
* the hash of all signers' commitments
* nonce_commitments_hash_is_set: If `has_secret_data`, whether the
* nonce_commitments_hash has been set
*/
typedef struct {
secp256k1_pubkey combined_pk;
uint32_t n_signers;
unsigned char pk_hash[32];
secp256k1_pubkey combined_nonce;
int nonce_is_set;
int nonce_is_negated;
unsigned char msg[32];
int msg_is_set;
int has_secret_data;
unsigned char seckey[32];
unsigned char secnonce[32];
secp256k1_pubkey nonce;
unsigned char nonce_commitments_hash[32];
int nonce_commitments_hash_is_set;
} secp256k1_musig_session;
/** Data structure containing data on all signers in a single session.
*
* The workflow for this structure is as follows:
*
* 1. This structure is initialized with `musig_session_initialize` or
* `musig_session_initialize_verifier`, which set the `index` field, and zero out
* all other fields. The public session is initialized with the signers'
* nonce_commitments.
*
* 2. In a non-public session the nonce_commitments are set with the function
* `musig_get_public_nonce`, which also returns the signer's public nonce. This
* ensures that the public nonce is not exposed until all commitments have been
* received.
*
* 3. Each individual data struct should be updated with `musig_set_nonce` once a
* nonce is available. This function takes a single signer data struct rather than
* an array because it may fail in the case that the provided nonce does not match
* the commitment. In this case, it is desirable to identify the exact party whose
* nonce was inconsistent.
*
* Fields:
* present: indicates whether the signer's nonce is set
* index: index of the signer in the MuSig key aggregation
* nonce: public nonce, must be a valid curvepoint if the signer is `present`
* nonce_commitment: commitment to the nonce, or all-bits zero if a commitment
* has not yet been set
*/
typedef struct {
int present;
uint32_t index;
secp256k1_pubkey nonce;
unsigned char nonce_commitment[32];
} secp256k1_musig_session_signer_data;
/** Opaque data structure that holds a MuSig partial signature.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is however
* guaranteed to be 32 bytes in size, and can be safely copied/moved. If you need
* to convert to a format suitable for storage, transmission, or comparison, use the
* `musig_partial_signature_serialize` and `musig_partial_signature_parse`
* functions.
*/
typedef struct {
unsigned char data[32];
} secp256k1_musig_partial_signature;
/** Computes a combined public key and the hash of the given public keys
*
* Returns: 1 if the public keys were successfully combined, 0 otherwise
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
* scratch: scratch space used to compute the combined pubkey by
* multiexponentiation. If NULL, an inefficient algorithm is used.
* Out: combined_pk: the MuSig-combined public key (cannot be NULL)
* pk_hash32: if non-NULL, filled with the 32-byte hash of all input public
* keys in order to be used in `musig_session_initialize`.
* In: pubkeys: input array of public keys to combine. The order is important;
* a different order will result in a different combined public
* key (cannot be NULL)
* n_pubkeys: length of pubkeys array
*/
#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,
unsigned char *pk_hash32,
const secp256k1_pubkey *pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
/** 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)
*/
#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,
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
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11);
/** 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.
*/
#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,
secp256k1_pubkey *nonce,
const unsigned char *const *commitments,
size_t n_commitments
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Initializes a verifier session that can be used for verifying nonce commitments
* and partial signatures. It does not have secret key material and therefore can not
* be used to create signatures.
*
* Returns: 1 when session is successfully initialized, 0 otherwise
* Args: ctx: pointer to a context object (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)
* In: msg32: the 32-byte message to be signed If NULL, must be set with
* `musig_session_set_msg` before using the session for verifying
* partial signatures.
* 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)
* commitments: array of 32-byte nonce commitments. Array length must equal to
* `n_signers` (cannot be NULL)
* n_signers: length of signers and commitments array. Number of signers
* participating in the MuSig. Must be greater than 0 and at most
* 2^32 - 1.
*/
#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,
const unsigned char *msg32,
const secp256k1_pubkey *combined_pk,
const unsigned char *pk_hash32,
const unsigned char *const *commitments,
size_t n_signers
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
/** 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)
*/
#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
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** 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.
*/
#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,
size_t n_signers,
int *nonce_is_negated,
const secp256k1_pubkey *adaptor
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Sets the message of a session if previously unset
*
* Returns 1 if the message was not set yet and is now successfully set
* 0 otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* session: the session structure to update with the message (cannot be NULL)
* In: msg32: the 32-byte message to be signed (cannot be NULL)
*/
#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
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a MuSig partial signature or adaptor signature
*
* Returns: 1 when the signature could be serialized, 0 otherwise
* Args: ctx: a secp256k1 context object
* Out: out32: pointer to a 32-byte array to store the serialized signature
* In: sig: pointer to the signature
*/
#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
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse and verify a MuSig partial signature.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
* Args: ctx: a secp256k1 context object
* Out: sig: pointer to a signature object
* In: in32: pointer to the 32-byte signature to be parsed
*
* After the call, sig will always be initialized. If parsing failed or the
* encoded numbers are out of range, signature verification with it is
* guaranteed to fail for every message and public key.
*/
#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
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Produces a partial signature
*
* Returns: 1: partial signature constructed
* 0: session in incorrect or inconsistent state
* Args: ctx: pointer to a context object (cannot be NULL)
* session: active signing session for which the combined nonce has been
* computed (cannot be NULL)
* Out: partial_sig: partial signature (cannot be NULL)
*/
#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
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Checks that an individual partial signature verifies
*
* This function is essential when using protocols with adaptor signatures.
* However, it is not essential for regular MuSig's, in the sense that if any
* partial signatures does not verify, the full signature will also not verify, so the
* problem will be caught. But this function allows determining the specific party
* who produced an invalid signature, so that signing can be restarted without them.
*
* Returns: 1: partial signature verifies
* 0: invalid signature or bad data
* Args: ctx: pointer to a context object (cannot be NULL)
* session: active session for which the combined nonce has been computed
* (cannot be NULL)
* signer: data for the signer who produced this signature (cannot be NULL)
* In: partial_sig: signature to verify (cannot be NULL)
* pubkey: public key of the signer who produced the signature (cannot be NULL)
*/
#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,
const secp256k1_musig_partial_signature *partial_sig,
const secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Combines partial signatures
*
* Returns: 1: all partial signatures have values in range. Does NOT mean the
* resulting signature verifies.
* 0: some partial signature had s/r out of range
* Args: ctx: pointer to a context object (cannot be NULL)
* session: initialized session for which the combined nonce has been
* computed (cannot be NULL)
* Out: sig: complete signature (cannot be NULL)
* In: partial_sigs: array of partial signatures to combine (cannot be NULL)
* n_sigs: number of signatures in the partial_sigs array
*/
#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,
const secp256k1_musig_partial_signature *partial_sigs,
size_t n_sigs
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Converts a partial signature to an adaptor signature by adding a given secret
* adaptor.
*
* Returns: 1: signature and secret adaptor contained valid values
* 0: otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: adaptor_sig: adaptor signature to produce (cannot be NULL)
* In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL)
* sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot
* be NULL)
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces`
*/
#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,
const unsigned char *sec_adaptor32,
int nonce_is_negated
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Extracts a secret adaptor from a MuSig, given all parties' partial
* signatures. This function will not fail unless given grossly invalid data; if it
* is merely given signatures that do not verify, the returned value will be
* nonsense. It is therefore important that all data be verified at earlier steps of
* any protocol that uses this function.
*
* Returns: 1: signatures contained valid data such that an adaptor could be extracted
* 0: otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL)
* In: sig: complete 2-of-2 signature (cannot be NULL)
* partial_sigs: array of partial signatures (cannot be NULL)
* n_partial_sigs: number of elements in partial_sigs array
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces`
*/
#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,
const secp256k1_musig_partial_signature *partial_sigs,
size_t n_partial_sigs,
int nonce_is_negated
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#endif

129
src/secp256k1/include/secp256k1_schnorrsig.h

@ -0,0 +1,129 @@
#ifndef SECP256K1_SCHNORRSIG_H
#define SECP256K1_SCHNORRSIG_H
/** This module implements a variant of Schnorr signatures compliant with
* BIP-schnorr
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki).
*/
/** Opaque data structure that holds a parsed Schnorr signature.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use the `secp256k1_schnorrsig_serialize` and
* `secp256k1_schnorrsig_parse` functions.
*/
typedef struct {
unsigned char data[64];
} secp256k1_schnorrsig;
/** Serialize a Schnorr signature.
*
* Returns: 1
* Args: ctx: a secp256k1 context object
* Out: out64: pointer to a 64-byte array to store the serialized signature
* In: sig: pointer to the signature
*
* See secp256k1_schnorrsig_parse for details about the encoding.
*/
#ifdef __cplusplus
extern "C"
#else
SECP256K1_API
#endif
int secp256k1_schnorrsig_serialize(
const secp256k1_context* ctx,
unsigned char *out64,
const secp256k1_schnorrsig* sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse a Schnorr signature.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
* Args: ctx: a secp256k1 context object
* Out: sig: pointer to a signature object
* In: in64: pointer to the 64-byte signature to be parsed
*
* The signature is serialized in the form R||s, where R is a 32-byte public
* key (x-coordinate only; the y-coordinate is considered to be the unique
* y-coordinate satisfying the curve equation that is a quadratic residue)
* and s is a 32-byte big-endian scalar.
*
* After the call, sig will always be initialized. If parsing failed or the
* encoded numbers are out of range, signature validation with it is
* guaranteed to fail for every message and public key.
*/
#ifdef __cplusplus
extern "C"
#else
SECP256K1_API
#endif
int secp256k1_schnorrsig_parse(
const secp256k1_context* ctx,
secp256k1_schnorrsig* sig,
const unsigned char *in64
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Create a Schnorr signature.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to the returned signature (cannot be NULL)
* nonce_is_negated: a pointer to an integer indicates if signing algorithm negated the
* nonce (can be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
*/
SECP256K1_API int secp256k1_schnorrsig_sign(
const secp256k1_context* ctx,
secp256k1_schnorrsig *sig,
int *nonce_is_negated,
const unsigned char *msg32,
const unsigned char *seckey,
secp256k1_nonce_function noncefp,
void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Verify a Schnorr signature.
*
* Returns: 1: correct signature
* 0: incorrect or unparseable signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature being verified (cannot be NULL)
* msg32: the 32-byte message hash being verified (cannot be NULL)
* pubkey: pointer to a public key to verify with (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
const secp256k1_context* ctx,
const secp256k1_schnorrsig *sig,
const unsigned char *msg32,
const secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Verifies a set of Schnorr signatures.
*
* Returns 1 if all succeeded, 0 otherwise. In particular, returns 1 if n_sigs is 0.
*
* Args: ctx: a secp256k1 context object, initialized for verification.
* scratch: scratch space used for the multiexponentiation
* In: sig: array of signatures, or NULL if there are no signatures
* msg32: array of messages, or NULL if there are no signatures
* pk: array of public keys, or NULL if there are no signatures
* n_sigs: number of signatures in above arrays. Must be smaller than
* 2^31 and smaller than half the maximum size_t value. Must be 0
* if above arrays are NULL.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch(
const secp256k1_context* ctx,
secp256k1_scratch_space *scratch,
const secp256k1_schnorrsig *const *sig,
const unsigned char *const *msg32,
const secp256k1_pubkey *const *pk,
size_t n_sigs
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
#endif

59
src/secp256k1/src/ecmult.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
@ -29,3 +31,60 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
#endif /* SECP256K1_ECMULT_H */
#else
/**********************************************************************
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_H
#define SECP256K1_ECMULT_H
#include "num.h"
#include "group.h"
#include "scalar.h"
#include "scratch.h"
typedef struct {
/* For accelerating the computation of a*P + b*G: */
secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */
#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
#endif
} secp256k1_ecmult_context;
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
/** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
/**
* Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai.
* Chooses the right algorithm for a given number of points and scratch space
* size. Resets and overwrites the given scratch space. If the points do not
* fit in the scratch space the algorithm is repeatedly run with batches of
* points. If no scratch space is given then a simple algorithm is used that
* simply multiplies the points with the corresponding scalars and adds them up.
* Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
* 0 if there is not enough scratch space for a single point or
* callback returns 0
*/
#ifdef __cplusplus
extern "C"
#endif
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);
#endif /* SECP256K1_ECMULT_H */
#endif

23
src/secp256k1/src/ecmult_const.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
@ -13,3 +15,24 @@
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
#endif /* SECP256K1_ECMULT_CONST_H */
#else
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_H
#define SECP256K1_ECMULT_CONST_H
#include "scalar.h"
#include "group.h"
/* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
* one because we internally sometimes add 2 to the number during the WNAF conversion. */
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
#endif /* SECP256K1_ECMULT_CONST_H */
#endif

273
src/secp256k1/src/ecmult_const_impl.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
@ -12,6 +14,7 @@
#include "ecmult_const.h"
#include "ecmult_impl.h"
#ifdef USE_ENDOMORPHISM
#define WNAF_BITS 128
#else
@ -238,3 +241,273 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
}
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
#else
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_IMPL_H
#define SECP256K1_ECMULT_CONST_IMPL_H
#include "scalar.h"
#include "group.h"
#include "ecmult_const.h"
#include "ecmult_impl.h"
#ifdef USE_ENDOMORPHISM
#define WNAF_BITS 128
#else
#define WNAF_BITS 256
#endif
#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w))
#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w)
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
int m; \
int abs_n = (n) * (((n) > 0) * 2 - 1); \
int idx_n = abs_n / 2; \
secp256k1_fe neg_y; \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
/* This loop is used to avoid secret data in array indices. See
* the comment in ecmult_gen_impl.h for rationale. */ \
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \
} \
(r)->infinity = 0; \
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \
} while(0)
/** Convert a number to WNAF notation.
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
* It has the following guarantees:
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
* - each wnaf[i] is nonzero
* - the number of words set is always WNAF_SIZE(w) + 1
*
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
* CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003
*
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
*/
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) {
int global_sign;
int skew = 0;
int word = 0;
/* 1 2 3 */
int u_last;
int u;
int flip;
int bit;
secp256k1_scalar neg_s;
int not_neg_one;
/* Note that we cannot handle even numbers by negating them to be odd, as is
* done in other implementations, since if our scalars were specified to have
* width < 256 for performance reasons, their negations would have width 256
* and we'd lose any performance benefit. Instead, we use a technique from
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
* this, and having the caller compensate after doing the multiplication.
*
* In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
* particular, to ensure that the outputs from the endomorphism-split fit into
* 128 bits). If we negate, the parity of our number flips, inverting which of
* {1, 2} we want to add to the scalar when ensuring that it's odd. Further
* complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
* we need to special-case it in this logic. */
flip = secp256k1_scalar_is_high(&s);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ !secp256k1_scalar_is_even(&s);
/* We check for negative one, since adding 2 to it will cause an overflow */
secp256k1_scalar_negate(&neg_s, &s);
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
* that we added two to it and flipped it. In fact for -1 these operations are
* identical. We only flipped, but since skewing is required (in the sense that
* the skew must be 1 or 2, never zero) and flipping is not, we need to change
* our flags to claim that we only skewed. */
global_sign = secp256k1_scalar_cond_negate(&s, flip);
global_sign *= not_neg_one * 2 - 1;
skew = 1 << bit;
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
while (word * w < size) {
int sign;
int even;
/* 4.1 4.4 */
u = secp256k1_scalar_shr_int(&s, w);
/* 4.2 */
even = ((u & 1) == 0);
sign = 2 * (u_last > 0) - 1;
u += sign * even;
u_last -= sign * even * (1 << w);
/* 4.3, adapted for global sign change */
wnaf[word++] = u_last * global_sign;
u_last = u;
}
wnaf[word] = u * global_sign;
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
return skew;
}
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge tmpa;
secp256k1_fe Z;
int skew_1;
#ifdef USE_ENDOMORPHISM
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
int skew_lam;
secp256k1_scalar q_1, q_lam;
#endif
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
int i;
secp256k1_scalar sc = *scalar;
/* build wnaf representation for q. */
int rsize = size;
#ifdef USE_ENDOMORPHISM
if (size > 128) {
rsize = 128;
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128);
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128);
} else
#endif
{
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size);
#ifdef USE_ENDOMORPHISM
skew_lam = 0;
#endif
}
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
* that the Z coordinate was 1, use affine addition formulae, and correct
* the Z coordinate of the result once at the end.
*/
secp256k1_gej_set_ge(r, a);
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_fe_normalize_weak(&pre_a[i].y);
}
#ifdef USE_ENDOMORPHISM
if (size > 128) {
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
}
#endif
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
secp256k1_gej_add_ge(r, r, &tmpa);
}
#endif
/* remaining loop iterations */
for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
secp256k1_gej_double_nonzero(r, r, NULL);
}
n = wnaf_1[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
n = wnaf_lam[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
}
#endif
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
{
/* Correct for wNAF skew */
secp256k1_ge correction = *a;
secp256k1_ge_storage correction_1_stor;
#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage correction_lam_stor;
#endif
secp256k1_ge_storage a2_stor;
secp256k1_gej tmpj;
secp256k1_gej_set_ge(&tmpj, &correction);
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
secp256k1_ge_set_gej(&correction, &tmpj);
secp256k1_ge_to_storage(&correction_1_stor, a);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
secp256k1_ge_to_storage(&correction_lam_stor, a);
}
#endif
secp256k1_ge_to_storage(&a2_stor, &correction);
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
}
#endif
/* Apply the correction */
secp256k1_ge_from_storage(&correction, &correction_1_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_ge_mul_lambda(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
}
#endif
}
}
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
#endif

1176
src/secp256k1/src/ecmult_impl.h

File diff suppressed because it is too large

2
src/secp256k1/src/modules/ecdh/main_impl.h

@ -30,7 +30,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
unsigned char y[1];
secp256k1_sha256 sha;
secp256k1_ecmult_const(&res, &pt, &s);
secp256k1_ecmult_const(&res, &pt, &s,256);
secp256k1_ge_set_gej(&pt, &res);
/* Compute a hash of the point in compressed form
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not

17
src/secp256k1/src/modules/musig/Makefile.am.include

@ -0,0 +1,17 @@
include_HEADERS += include/secp256k1_musig.h
noinst_HEADERS += src/modules/musig/main_impl.h
noinst_HEADERS += src/modules/musig/tests_impl.h
noinst_PROGRAMS += example_musig
example_musig_SOURCES = src/modules/musig/example.c
example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES)
if !ENABLE_COVERAGE
example_musig_CPPFLAGS += -DVERIFY
endif
example_musig_LDADD = libsecp256k1.la $(SECP_LIBS)
example_musig_LDFLAGS = -static
if USE_TESTS
TESTS += example_musig
endif

166
src/secp256k1/src/modules/musig/example.c

@ -0,0 +1,166 @@
/**********************************************************************
* Copyright (c) 2018 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/**
* This file demonstrates how to use the MuSig module to create a multisignature.
* Additionally, see the documentation in include/secp256k1_musig.h.
*/
/*#include <stdio.h>
#include <assert.h>
#include <secp256k1.h>
#include <secp256k1_schnorrsig.h>
#include <secp256k1_musig.h>*/
/* Number of public keys involved in creating the aggregate signature */
#define N_SIGNERS 3
/* Create a key pair and store it in seckey and pubkey */
int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pubkey* pubkey) {
int ret;
FILE *frand = fopen("/dev/urandom", "r");
if (frand == NULL) {
return 0;
}
do {
if(!fread(seckey, 32, 1, frand)) {
fclose(frand);
return 0;
}
/* The probability that this not a valid secret key is approximately 2^-128 */
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
fclose(frand);
ret = secp256k1_ec_pubkey_create(ctx, pubkey, seckey);
return ret;
}
/* Sign a message hash with the given key pairs and store the result in sig */
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_pubkey* pubkeys, const unsigned char* msg32, secp256k1_schnorrsig *sig) {
secp256k1_musig_session musig_session[N_SIGNERS];
unsigned char nonce_commitment[N_SIGNERS][32];
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS];
secp256k1_pubkey nonce[N_SIGNERS];
int i, j;
secp256k1_musig_partial_signature partial_sig[N_SIGNERS];
for (i = 0; i < N_SIGNERS; i++) {
FILE *frand;
unsigned char session_id32[32];
unsigned char pk_hash[32];
secp256k1_pubkey combined_pk;
/* Create combined pubkey and initialize signer data */
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, pk_hash, pubkeys, N_SIGNERS)) {
return 0;
}
/* Create random session ID. It is absolutely necessary that the session ID
* is unique for every call of secp256k1_musig_session_initialize. Otherwise
* it's trivial for an attacker to extract the secret key! */
frand = fopen("/dev/urandom", "r");
if(frand == NULL) {
return 0;
}
if (!fread(session_id32, 32, 1, frand)) {
fclose(frand);
return 0;
}
fclose(frand);
/* Initialize session */
if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, N_SIGNERS, i, seckeys[i])) {
return 0;
}
nonce_commitment_ptr[i] = &nonce_commitment[i][0];
}
/* Communication round 1: Exchange nonce commitments */
for (i = 0; i < N_SIGNERS; i++) {
/* Set nonce commitments in the signer data and get the own public nonce */
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS)) {
return 0;
}
}
/* Communication round 2: Exchange nonces */
for (i = 0; i < N_SIGNERS; i++) {
for (j = 0; j < N_SIGNERS; j++) {
if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], &nonce[j])) {
/* Signer j's nonce does not match the nonce commitment. In this case
* abort the protocol. If you make another attempt at finishing the
* protocol, create a new session (with a fresh session ID!). */
return 0;
}
}
if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) {
return 0;
}
}
for (i = 0; i < N_SIGNERS; i++) {
if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) {
return 0;
}
}
/* Communication round 3: Exchange partial signatures */
for (i = 0; i < N_SIGNERS; i++) {
for (j = 0; j < N_SIGNERS; j++) {
/* To check whether signing was successful, it suffices to either verify
* the the combined signature with the combined public key using
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
* signers individually. Verifying the combined signature is cheaper but
* verifying the individual partial signatures has the advantage that it
* can be used to determine which of the partial signatures are invalid
* (if any), i.e., which of the partial signatures cause the combined
* signature to be invalid and thus the protocol run to fail. It's also
* fine to first verify the combined sig, and only verify the individual
* sigs if it does not work.
*/
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) {
return 0;
}
}
}
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS);
}
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";
secp256k1_schnorrsig sig;
/* Create a context for signing and verification */
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
fprintf(stderr,"Creating key pairs......");
for (i = 0; i < N_SIGNERS; i++) {
if (!create_key(ctx, seckeys[i], &pubkeys[i])) {
fprintf(stderr,"FAILED\n");
return 1;
}
}
fprintf(stderr,"ok\n");
fprintf(stderr,"Combining public keys...");
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) {
fprintf(stderr,"FAILED\n");
return 1;
}
fprintf(stderr,"ok\n");
fprintf(stderr,"Signing message.........");
if (!sign(ctx, seckeys, pubkeys, msg, &sig)) {
fprintf(stderr,"FAILED\n");
return 1;
}
fprintf(stderr,"ok\n");
fprintf(stderr,"Verifying signature.....");
if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) {
fprintf(stderr,"FAILED\n");
return 1;
}
fprintf(stderr,"ok\n");
secp256k1_context_destroy(ctx);
return 0;
}

631
src/secp256k1/src/modules/musig/main_impl.h

@ -0,0 +1,631 @@
/**********************************************************************
* Copyright (c) 2018 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_MUSIG_MAIN_
#define _SECP256K1_MODULE_MUSIG_MAIN_
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_musig.h"
#include "hash.h"
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_pubkey *pk, size_t np) {
secp256k1_sha256 sha;
size_t i;
secp256k1_sha256_initialize(&sha);
for (i = 0; i < np; i++) {
unsigned char ser[33];
size_t serlen = sizeof(ser);
if (!secp256k1_ec_pubkey_serialize(ctx, ser, &serlen, &pk[i], SECP256K1_EC_COMPRESSED)) {
return 0;
}
secp256k1_sha256_write(&sha, ser, serlen);
}
secp256k1_sha256_finalize(&sha, ell);
return 1;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */
static void secp256k1_musig_sha256_init_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0x0fd0690cul;
sha->s[1] = 0xfefeae97ul;
sha->s[2] = 0x996eac7ful;
sha->s[3] = 0x5c30d864ul;
sha->s[4] = 0x8c4a0573ul;
sha->s[5] = 0xaca1a22ful;
sha->s[6] = 0x6f43b801ul;
sha->s[7] = 0x85ce27cdul;
sha->bytes = 64;
}
/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */
static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char *ell, uint32_t idx) {
secp256k1_sha256 sha;
unsigned char buf[32];
size_t i;
secp256k1_musig_sha256_init_tagged(&sha);
secp256k1_sha256_write(&sha, ell, 32);
/* We're hashing the index of the signer instead of its public key as specified
* in the MuSig paper. This reduces the total amount of data that needs to be
* hashed.
* Additionally, it prevents creating identical musig_coefficients for identical
* public keys. A participant Bob could choose his public key to be the same as
* Alice's, then replay Alice's messages (nonce and partial signature) to create
* a valid partial signature. This is not a problem for MuSig per se, but could
* result in subtle issues with protocols building on threshold signatures.
* With the assumption that public keys are unique, hashing the index is
* equivalent to hashing the public key. Because the public key can be
* identified by the index given the ordered list of public keys (included in
* ell), the index is just a different encoding of the public key.*/
for (i = 0; i < sizeof(uint32_t); i++) {
unsigned char c = idx;
secp256k1_sha256_write(&sha, &c, 1);
idx >>= 8;
}
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(r, buf, NULL);
}
typedef struct {
const secp256k1_context *ctx;
unsigned char ell[32];
const secp256k1_pubkey *pks;
} secp256k1_musig_pubkey_combine_ecmult_data;
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data;
secp256k1_musig_coefficient(sc, ctx->ell, idx);
return secp256k1_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
}
static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) {
uint32_t i;
for (i = 0; i < n_signers; i++) {
memset(&signers[i], 0, sizeof(signers[i]));
signers[i].index = i;
signers[i].present = 0;
}
}
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) {
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
secp256k1_gej pkj;
secp256k1_ge pkp;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(pubkeys != NULL);
ARG_CHECK(n_pubkeys > 0);
ecmult_data.ctx = ctx;
ecmult_data.pks = pubkeys;
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
return 0;
}
if (!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
return 0;
}
secp256k1_ge_set_gej(&pkp, &pkj);
secp256k1_pubkey_save(combined_pk, &pkp);
if (pk_hash32 != NULL) {
memcpy(pk_hash32, ecmult_data.ell, 32);
}
return 1;
}
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) {
unsigned char combined_ser[33];
size_t combined_ser_size = sizeof(combined_ser);
int overflow;
secp256k1_scalar secret;
secp256k1_scalar mu;
secp256k1_sha256 sha;
secp256k1_gej rj;
secp256k1_ge rp;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(nonce_commitment32 != NULL);
ARG_CHECK(session_id32 != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(pk_hash32 != NULL);
ARG_CHECK(seckey != NULL);
memset(session, 0, sizeof(*session));
if (msg32 != NULL) {
memcpy(session->msg, msg32, 32);
session->msg_is_set = 1;
} else {
session->msg_is_set = 0;
}
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
memcpy(session->pk_hash, pk_hash32, 32);
session->nonce_is_set = 0;
session->has_secret_data = 1;
if (n_signers == 0 || my_index >= n_signers) {
return 0;
}
if (n_signers > UINT32_MAX) {
return 0;
}
session->n_signers = (uint32_t) n_signers;
secp256k1_musig_signers_init(signers, session->n_signers);
session->nonce_commitments_hash_is_set = 0;
/* Compute secret key */
secp256k1_scalar_set_b32(&secret, seckey, &overflow);
if (overflow) {
secp256k1_scalar_clear(&secret);
return 0;
}
secp256k1_musig_coefficient(&mu, pk_hash32, (uint32_t) my_index);
secp256k1_scalar_mul(&secret, &secret, &mu);
secp256k1_scalar_get_b32(session->seckey, &secret);
/* Compute secret nonce */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, session_id32, 32);
if (session->msg_is_set) {
secp256k1_sha256_write(&sha, msg32, 32);
}
secp256k1_ec_pubkey_serialize(ctx, combined_ser, &combined_ser_size, combined_pk, SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(&sha, combined_ser, combined_ser_size);
secp256k1_sha256_write(&sha, seckey, 32);
secp256k1_sha256_finalize(&sha, session->secnonce);
secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow);
if (overflow) {
secp256k1_scalar_clear(&secret);
return 0;
}
/* Compute public nonce and commitment */
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &secret);
secp256k1_ge_set_gej(&rp, &rj);
secp256k1_pubkey_save(&session->nonce, &rp);
if (nonce_commitment32 != NULL) {
unsigned char commit[33];
size_t commit_size = sizeof(commit);
secp256k1_sha256_initialize(&sha);
secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, &session->nonce, SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(&sha, commit, commit_size);
secp256k1_sha256_finalize(&sha, nonce_commitment32);
}
secp256k1_scalar_clear(&secret);
return 1;
}
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, secp256k1_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments) {
secp256k1_sha256 sha;
unsigned char nonce_commitments_hash[32];
size_t i;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(nonce != NULL);
ARG_CHECK(commitments != NULL);
if (!session->has_secret_data || n_commitments != session->n_signers) {
return 0;
}
for (i = 0; i < n_commitments; i++) {
ARG_CHECK(commitments[i] != NULL);
}
secp256k1_sha256_initialize(&sha);
for (i = 0; i < n_commitments; i++) {
memcpy(signers[i].nonce_commitment, commitments[i], 32);
secp256k1_sha256_write(&sha, commitments[i], 32);
}
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
if (session->nonce_commitments_hash_is_set
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
/* Abort if get_public_nonce has been called before with a different array of
* commitments. */
return 0;
}
memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32);
session->nonce_commitments_hash_is_set = 1;
memcpy(nonce, &session->nonce, sizeof(*nonce));
return 1;
}
int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, const unsigned char *const *commitments, size_t n_signers) {
size_t i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(pk_hash32 != NULL);
ARG_CHECK(commitments != NULL);
/* Check n_signers before checking commitments to allow testing the case where
* n_signers is big without allocating the space. */
if (n_signers > UINT32_MAX) {
return 0;
}
for (i = 0; i < n_signers; i++) {
ARG_CHECK(commitments[i] != NULL);
}
(void) ctx;
memset(session, 0, sizeof(*session));
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
if (n_signers == 0) {
return 0;
}
session->n_signers = (uint32_t) n_signers;
secp256k1_musig_signers_init(signers, session->n_signers);
memcpy(session->pk_hash, pk_hash32, 32);
session->nonce_is_set = 0;
session->msg_is_set = 0;
if (msg32 != NULL) {
memcpy(session->msg, msg32, 32);
session->msg_is_set = 1;
}
session->has_secret_data = 0;
session->nonce_commitments_hash_is_set = 0;
for (i = 0; i < n_signers; i++) {
memcpy(signers[i].nonce_commitment, commitments[i], 32);
}
return 1;
}
int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const secp256k1_pubkey *nonce) {
unsigned char commit[33];
size_t commit_size = sizeof(commit);
secp256k1_sha256 sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(signer != NULL);
ARG_CHECK(nonce != NULL);
secp256k1_sha256_initialize(&sha);
secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, nonce, SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(&sha, commit, commit_size);
secp256k1_sha256_finalize(&sha, commit);
if (memcmp(commit, signer->nonce_commitment, 32) != 0) {
return 0;
}
memcpy(&signer->nonce, nonce, sizeof(*nonce));
signer->present = 1;
return 1;
}
int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_is_negated, const secp256k1_pubkey *adaptor) {
secp256k1_gej combined_noncej;
secp256k1_ge combined_noncep;
secp256k1_ge noncep;
secp256k1_sha256 sha;
unsigned char nonce_commitments_hash[32];
size_t i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
if (n_signers != session->n_signers) {
return 0;
}
secp256k1_sha256_initialize(&sha);
secp256k1_gej_set_infinity(&combined_noncej);
for (i = 0; i < n_signers; i++) {
if (!signers[i].present) {
return 0;
}
secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32);
secp256k1_pubkey_load(ctx, &noncep, &signers[i].nonce);
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
}
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
/* Either the session is a verifier session or or the nonce_commitments_hash has
* been set in `musig_session_get_public_nonce`. */
VERIFY_CHECK(!session->has_secret_data || session->nonce_commitments_hash_is_set);
if (session->has_secret_data
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
/* If the signers' commitments changed between get_public_nonce and now we
* have to abort because in that case they may have seen our nonce before
* creating their commitment. That can happen if the signer_data given to
* this function is different to the signer_data given to get_public_nonce.
* */
return 0;
}
/* Add public adaptor to nonce */
if (adaptor != NULL) {
secp256k1_pubkey_load(ctx, &noncep, adaptor);
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
}
secp256k1_ge_set_gej(&combined_noncep, &combined_noncej);
if (secp256k1_fe_is_quad_var(&combined_noncep.y)) {
session->nonce_is_negated = 0;
} else {
session->nonce_is_negated = 1;
secp256k1_ge_neg(&combined_noncep, &combined_noncep);
}
if (nonce_is_negated != NULL) {
*nonce_is_negated = session->nonce_is_negated;
}
secp256k1_pubkey_save(&session->combined_nonce, &combined_noncep);
session->nonce_is_set = 1;
return 1;
}
int secp256k1_musig_session_set_msg(const secp256k1_context* ctx, secp256k1_musig_session *session, const unsigned char *msg32) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(msg32 != NULL);
if (session->msg_is_set) {
return 0;
}
memcpy(session->msg, msg32, 32);
session->msg_is_set = 1;
return 1;
}
int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(out32 != NULL);
ARG_CHECK(sig != NULL);
memcpy(out32, sig->data, 32);
return 1;
}
int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(in32 != NULL);
memcpy(sig->data, in32, 32);
return 1;
}
/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */
static int secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) {
unsigned char buf[33];
size_t bufsize = 33;
secp256k1_ge rp;
secp256k1_sha256 sha;
secp256k1_sha256_initialize(&sha);
if (!session->nonce_is_set) {
return 0;
}
secp256k1_pubkey_load(ctx, &rp, &session->combined_nonce);
secp256k1_fe_get_b32(buf, &rp.x);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_ec_pubkey_serialize(ctx, buf, &bufsize, &session->combined_pk, SECP256K1_EC_COMPRESSED);
VERIFY_CHECK(bufsize == 33);
secp256k1_sha256_write(&sha, buf, bufsize);
if (!session->msg_is_set) {
return 0;
}
secp256k1_sha256_write(&sha, session->msg, 32);
secp256k1_sha256_finalize(&sha, msghash);
return 1;
}
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) {
unsigned char msghash[32];
int overflow;
secp256k1_scalar sk;
secp256k1_scalar e, k;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(partial_sig != NULL);
ARG_CHECK(session != NULL);
if (!session->nonce_is_set || !session->has_secret_data) {
return 0;
}
/* build message hash */
if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) {
return 0;
}
secp256k1_scalar_set_b32(&e, msghash, NULL);
secp256k1_scalar_set_b32(&sk, session->seckey, &overflow);
if (overflow) {
secp256k1_scalar_clear(&sk);
return 0;
}
secp256k1_scalar_set_b32(&k, session->secnonce, &overflow);
if (overflow || secp256k1_scalar_is_zero(&k)) {
secp256k1_scalar_clear(&sk);
secp256k1_scalar_clear(&k);
return 0;
}
if (session->nonce_is_negated) {
secp256k1_scalar_negate(&k, &k);
}
/* Sign */
secp256k1_scalar_mul(&e, &e, &sk);
secp256k1_scalar_add(&e, &e, &k);
secp256k1_scalar_get_b32(&partial_sig->data[0], &e);
secp256k1_scalar_clear(&sk);
secp256k1_scalar_clear(&k);
return 1;
}
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) {
size_t i;
secp256k1_scalar s;
secp256k1_ge noncep;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(partial_sigs != NULL);
ARG_CHECK(session != NULL);
if (!session->nonce_is_set) {
return 0;
}
if (n_sigs != session->n_signers) {
return 0;
}
secp256k1_scalar_clear(&s);
for (i = 0; i < n_sigs; i++) {
int overflow;
secp256k1_scalar term;
secp256k1_scalar_set_b32(&term, partial_sigs[i].data, &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_add(&s, &s, &term);
}
secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce);
VERIFY_CHECK(secp256k1_fe_is_quad_var(&noncep.y));
secp256k1_fe_normalize(&noncep.x);
secp256k1_fe_get_b32(&sig->data[0], &noncep.x);
secp256k1_scalar_get_b32(&sig->data[32], &s);
return 1;
}
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_pubkey *pubkey) {
unsigned char msghash[32];
secp256k1_scalar s;
secp256k1_scalar e;
secp256k1_scalar mu;
secp256k1_gej rj;
secp256k1_ge rp;
int overflow;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(session != NULL);
ARG_CHECK(signer != NULL);
ARG_CHECK(partial_sig != NULL);
ARG_CHECK(pubkey != NULL);
if (!session->nonce_is_set || !signer->present) {
return 0;
}
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
if (overflow) {
return 0;
}
if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) {
return 0;
}
secp256k1_scalar_set_b32(&e, msghash, NULL);
/* Multiplying the messagehash by the musig coefficient is equivalent
* to multiplying the signer's public key by the coefficient, except
* much easier to do. */
secp256k1_musig_coefficient(&mu, session->pk_hash, signer->index);
secp256k1_scalar_mul(&e, &e, &mu);
if (!secp256k1_pubkey_load(ctx, &rp, &signer->nonce)) {
return 0;
}
if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pubkey)) {
return 0;
}
if (!session->nonce_is_negated) {
secp256k1_ge_neg(&rp, &rp);
}
secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL);
return secp256k1_gej_is_infinity(&rj);
}
int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_is_negated) {
secp256k1_scalar s;
secp256k1_scalar t;
int overflow;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(adaptor_sig != NULL);
ARG_CHECK(partial_sig != NULL);
ARG_CHECK(sec_adaptor32 != NULL);
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow);
if (overflow) {
secp256k1_scalar_clear(&t);
return 0;
}
if (nonce_is_negated) {
secp256k1_scalar_negate(&t, &t);
}
secp256k1_scalar_add(&s, &s, &t);
secp256k1_scalar_get_b32(adaptor_sig->data, &s);
secp256k1_scalar_clear(&t);
return 1;
}
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) {
secp256k1_scalar t;
secp256k1_scalar s;
int overflow;
size_t i;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sec_adaptor32 != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(partial_sigs != NULL);
secp256k1_scalar_set_b32(&t, &sig->data[32], &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_negate(&t, &t);
for (i = 0; i < n_partial_sigs; i++) {
secp256k1_scalar_set_b32(&s, partial_sigs[i].data, &overflow);
if (overflow) {
secp256k1_scalar_clear(&t);
return 0;
}
secp256k1_scalar_add(&t, &t, &s);
}
if (!nonce_is_negated) {
secp256k1_scalar_negate(&t, &t);
}
secp256k1_scalar_get_b32(sec_adaptor32, &t);
secp256k1_scalar_clear(&t);
return 1;
}
#endif

758
src/secp256k1/src/modules/musig/tests_impl.h

@ -0,0 +1,758 @@
/**********************************************************************
* Copyright (c) 2018 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_MUSIG_TESTS_
#define _SECP256K1_MODULE_MUSIG_TESTS_
#include "secp256k1_musig.h"
void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_scratch_space *scratch_small;
secp256k1_musig_session session[2];
secp256k1_musig_session verifier_session;
secp256k1_musig_session_signer_data signer0[2];
secp256k1_musig_session_signer_data signer1[2];
secp256k1_musig_session_signer_data verifier_signer_data[2];
secp256k1_musig_partial_signature partial_sig[2];
secp256k1_musig_partial_signature partial_sig_adapted[2];
secp256k1_musig_partial_signature partial_sig_overflow;
secp256k1_schnorrsig final_sig;
secp256k1_schnorrsig final_sig_cmp;
unsigned char buf[32];
unsigned char sk[2][32];
unsigned char ones[32];
unsigned char session_id[2][32];
unsigned char nonce_commitment[2][32];
int nonce_is_negated;
const unsigned char *ncs[2];
unsigned char msg[32];
unsigned char msghash[32];
secp256k1_pubkey combined_pk;
unsigned char pk_hash[32];
secp256k1_pubkey pk[2];
unsigned char sec_adaptor[32];
unsigned char sec_adaptor1[32];
secp256k1_pubkey adaptor;
/** setup **/
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
int ecount;
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
memset(ones, 0xff, 32);
secp256k1_rand256(session_id[0]);
secp256k1_rand256(session_id[1]);
secp256k1_rand256(sk[0]);
secp256k1_rand256(sk[1]);
secp256k1_rand256(msg);
secp256k1_rand256(sec_adaptor);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1);
/** main test body **/
/* Key combination */
ecount = 0;
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, pk_hash, pk, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, pk_hash, pk, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
CHECK(ecount == 2);
/* pubkey_combine does not require a scratch space */
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, pk_hash, pk, 2) == 1);
CHECK(ecount == 2);
/* If a scratch space is given it shouldn't be too small */
scratch_small = secp256k1_scratch_space_create(ctx, 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 0);
secp256k1_scratch_space_destroy(scratch_small);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, pk_hash, pk, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 2) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 0) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 0) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
/** Session creation **/
ecount = 0;
CHECK(secp256k1_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, pk_hash, 2, 0, sk[0]) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0);
CHECK(ecount == 8);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 0, 0, sk[0]) == 0);
CHECK(ecount == 8);
/* If more than UINT32_MAX fits in a size_t, test that session_initialize
* rejects n_signers that high. */
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0);
}
CHECK(ecount == 8);
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, NULL) == 0);
CHECK(ecount == 9);
/* secret key overflows */
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, ones) == 0);
CHECK(ecount == 9);
{
secp256k1_musig_session session_without_msg;
CHECK(secp256k1_musig_session_initialize(sign, &session_without_msg, signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_set_msg(none, &session_without_msg, msg) == 1);
CHECK(secp256k1_musig_session_set_msg(none, &session_without_msg, msg) == 0);
}
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1);
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
ecount = 0;
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 1);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, NULL, 2) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 0) == 0);
CHECK(ecount == 4);
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, ((size_t) UINT32_MAX) + 2) == 0);
}
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1);
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &verifier_session) == 0);
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &session[0]) == 0);
/** Signing step 0 -- exchange nonce commitments */
ecount = 0;
{
secp256k1_pubkey nonce;
/* Can obtain public nonce after commitments have been exchanged; still can't sign */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 0);
CHECK(ecount == 0);
}
/** Signing step 1 -- exchange nonces */
ecount = 0;
{
secp256k1_pubkey public_nonce[3];
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, &public_nonce[0], ncs, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], NULL, &public_nonce[0], ncs, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, NULL, ncs, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], NULL, 2) == 0);
CHECK(ecount == 4);
/* Number of commitments and number of signers are different */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 1) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, &public_nonce[1], ncs, 2) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[0], &public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[0]) == 0);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1);
CHECK(ecount == 4);
CHECK(secp256k1_musig_set_nonce(none, NULL, &public_nonce[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], NULL) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], &public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer1[1], &public_nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[0], &public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[1], &public_nonce[1]) == 1);
ecount = 0;
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, NULL, signer0, 2, &nonce_is_negated, &adaptor) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], NULL, 2, &nonce_is_negated, &adaptor) == 0);
CHECK(ecount == 2);
/* Number of signers differs from number during intialization */
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 1, &nonce_is_negated, &adaptor) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, NULL, &adaptor) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, NULL) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[1], signer0, 2, &nonce_is_negated, &adaptor) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &nonce_is_negated, &adaptor) == 1);
}
/** Signing step 2 -- partial signatures */
ecount = 0;
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_musig_partial_sign(none, NULL, &partial_sig[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_sign(none, &session[1], &partial_sig[1]) == 1);
/* observer can't sign */
CHECK(secp256k1_musig_partial_sign(none, &verifier_session, &partial_sig[2]) == 0);
CHECK(ecount == 2);
ecount = 0;
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_signature_serialize(none, NULL, &partial_sig[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], buf) == 1);
CHECK(secp256k1_musig_partial_signature_parse(none, NULL, buf) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig_overflow, ones) == 1);
/** Partial signature verification */
ecount = 0;
CHECK(secp256k1_musig_partial_sig_verify(none, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sig_verify(sign, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[1], &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[1], &partial_sig[1], &pk[1]) == 1);
CHECK(ecount == 6);
/** Adaptor signature verification */
memcpy(&partial_sig_adapted[1], &partial_sig[1], sizeof(partial_sig_adapted[1]));
ecount = 0;
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, nonce_is_negated) == 1);
CHECK(secp256k1_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], NULL, sec_adaptor, 0) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, nonce_is_negated) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], NULL, 0) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, nonce_is_negated) == 0);
CHECK(ecount == 3);
/** Signing combining and verification */
ecount = 0;
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1);
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1);
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2) == 0);
CHECK(ecount == 3);
{
secp256k1_musig_partial_signature partial_sig_tmp[2];
partial_sig_tmp[0] = partial_sig_adapted[0];
partial_sig_tmp[1] = partial_sig_overflow;
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2) == 0);
}
CHECK(ecount == 3);
/* Wrong number of partial sigs */
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(vrfy, &final_sig, msg, &combined_pk) == 1);
/** Secret adaptor can be extracted from signature */
ecount = 0;
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, nonce_is_negated) == 1);
CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0);
CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, &final_sig, partial_sig, 2, 0) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0);
CHECK(ecount == 2);
{
secp256k1_schnorrsig final_sig_tmp = final_sig;
memcpy(&final_sig_tmp.data[32], ones, 32);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0);
}
CHECK(ecount == 2);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, NULL, 2, 0) == 0);
CHECK(ecount == 3);
{
secp256k1_musig_partial_signature partial_sig_tmp[2];
partial_sig_tmp[0] = partial_sig[0];
partial_sig_tmp[1] = partial_sig_overflow;
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0);
}
CHECK(ecount == 3);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 0, 0) == 1);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, 1) == 1);
/** cleanup **/
memset(&session, 0, sizeof(session));
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
}
/* Initializes two sessions, one use the given parameters (session_id,
* nonce_commitments, etc.) except that `session_tmp` uses new signers with different
* public keys. The point of this test is to call `musig_session_get_public_nonce`
* with signers from `session_tmp` who have different public keys than the correct
* ones and return the resulting messagehash. This should not result in a different
* messagehash because the public keys of the signers are only used during session
* initialization. */
int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) {
secp256k1_musig_session session;
secp256k1_musig_session session_tmp;
unsigned char nonce_commitment[32];
secp256k1_musig_session_signer_data signers[2];
secp256k1_musig_session_signer_data signers_tmp[2];
unsigned char sk_dummy[32];
secp256k1_pubkey pks_tmp[2];
secp256k1_pubkey combined_pk_tmp;
unsigned char pk_hash_tmp[32];
secp256k1_pubkey nonce;
/* Set up signers with different public keys */
secp256k1_rand256(sk_dummy);
pks_tmp[0] = pks[0];
CHECK(secp256k1_ec_pubkey_create(ctx, &pks_tmp[1], sk_dummy) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, pk_hash_tmp, pks_tmp, 2) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 0, sk_dummy) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0);
/* Call get_public_nonce with different signers than the signers the session was
* initialized with. */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, &nonce, nonce_commitments, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, &nonce, nonce_commitments, 2) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
return secp256k1_musig_compute_messagehash(ctx, msghash, &session);
}
/* Creates a new session (with a different session id) and tries to use that session
* to combine nonces with given signers_other. This should fail, because the nonce
* commitments of signers_other do not match the nonce commitments the new session
* was initialized with. If do_test is 0, the correct signers are being used and
* therefore the function should return 1. */
int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) {
secp256k1_musig_session session;
secp256k1_musig_session_signer_data signers[2];
secp256k1_musig_session_signer_data *signers_to_use;
unsigned char nonce_commitment[32];
unsigned char session_id[32];
secp256k1_pubkey nonce;
const unsigned char *ncs[2];
/* Initialize new signers */
secp256k1_rand256(session_id);
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
secp256k1_musig_session_combine_nonces(ctx, &session, signers_other, 2, NULL, NULL);
if (do_test) {
signers_to_use = signers_other;
} else {
signers_to_use = signers;
}
return secp256k1_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL);
}
/* Recreates a session with the given session_id, signers, pk, msg etc. parameters
* and tries to sign and verify the other signers partial signature. Both should fail
* if msg is NULL. */
int musig_state_machine_missing_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
secp256k1_musig_session session;
secp256k1_musig_session_signer_data signers[2];
unsigned char nonce_commitment[32];
const unsigned char *ncs[2];
secp256k1_pubkey nonce;
secp256k1_musig_partial_signature partial_sig;
int partial_sign, partial_verify;
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
partial_sign = secp256k1_musig_partial_sign(ctx, &session, &partial_sig);
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, &signers[0], partial_sig_other, &pks[0]);
if (msg != NULL) {
/* Return 1 if both succeeded */
return partial_sign && partial_verify;
}
/* Return 0 if both failed */
return partial_sign || partial_verify;
}
/* Recreates a session with the given session_id, signers, pk, msg etc. parameters
* and tries to verify and combine partial sigs. If do_combine is 0, the
* combine_nonces step is left out. In that case verify and combine should fail and
* this function should return 0. */
int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_musig_partial_signature *partial_sig, int do_combine) {
secp256k1_musig_session session;
secp256k1_musig_session_signer_data signers[2];
unsigned char nonce_commitment[32];
const unsigned char *ncs[2];
secp256k1_pubkey nonce;
secp256k1_musig_partial_signature partial_sigs[2];
secp256k1_schnorrsig sig;
int partial_verify, sig_combine;
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
partial_sigs[0] = *partial_sig_other;
partial_sigs[1] = *partial_sig;
if (do_combine != 0) {
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
}
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, signers, partial_sig_other, &pks[0]);
sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2);
if (do_combine != 0) {
/* Return 1 if both succeeded */
return partial_verify && sig_combine;
}
/* Return 0 if both failed */
return partial_verify || sig_combine;
}
void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
size_t i;
secp256k1_musig_session session[2];
secp256k1_musig_session_signer_data signers0[2];
secp256k1_musig_session_signer_data signers1[2];
unsigned char nonce_commitment[2][32];
unsigned char session_id[2][32];
unsigned char msg[32];
unsigned char sk[2][32];
secp256k1_pubkey pk[2];
secp256k1_pubkey combined_pk;
unsigned char pk_hash[32];
secp256k1_pubkey nonce[2];
const unsigned char *ncs[2];
secp256k1_musig_partial_signature partial_sig[2];
unsigned char msghash1[32];
unsigned char msghash2[32];
/* Run state machine with the same objects twice to test that it's allowed to
* reinitialize session and session_signer_data. */
for (i = 0; i < 2; i++) {
/* Setup */
secp256k1_rand256(session_id[0]);
secp256k1_rand256(session_id[1]);
secp256k1_rand256(sk[0]);
secp256k1_rand256(sk[1]);
secp256k1_rand256(msg);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, pk_hash, pk, 2) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1);
/* Set nonce commitments */
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1);
/* Changing a nonce commitment is not okay */
ncs[1] = (unsigned char*) "this isn't a nonce commitment...";
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 0);
/* Repeating with the same nonce commitments is okay */
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1);
/* Get nonce for signer 1 */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2) == 1);
/* Set nonces */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1);
/* Can't set nonce that doesn't match nonce commitment */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[0]) == 0);
/* Set correct nonce */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1);
/* Combine nonces */
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
/* Not everyone is present from signer 1's view */
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 0);
/* Make everyone present */
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], &nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1);
/* Can't combine nonces from signers of a different session */
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0);
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1);
/* Partially sign */
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
/* Can't verify or sign until nonce is combined */
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 0);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
/* messagehash should be the same as a session whose get_public_nonce was called
* with different signers (i.e. they diff in public keys). This is because the
* public keys of the signers is set in stone when initializing the session. */
CHECK(secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]) == 1);
CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, pk_hash, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1);
CHECK(memcmp(msghash1, msghash2, 32) == 0);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1);
/* Wrong signature */
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0);
/* Can't sign or verify until msg is set */
CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], NULL) == 0);
CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], msg) == 1);
/* Can't verify and combine partial sigs until nonces are combined */
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0);
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1);
}
}
void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
/* Throughout this test "a" and "b" refer to two hypothetical blockchains,
* while the indices 0 and 1 refer to the two signers. Here signer 0 is
* sending a-coins to signer 1, while signer 1 is sending b-coins to signer
* 0. Signer 0 produces the adaptor signatures. */
secp256k1_schnorrsig final_sig_a;
secp256k1_schnorrsig final_sig_b;
secp256k1_musig_partial_signature partial_sig_a[2];
secp256k1_musig_partial_signature partial_sig_b_adapted[2];
secp256k1_musig_partial_signature partial_sig_b[2];
unsigned char sec_adaptor[32];
unsigned char sec_adaptor_extracted[32];
secp256k1_pubkey pub_adaptor;
unsigned char seckey_a[2][32];
unsigned char seckey_b[2][32];
secp256k1_pubkey pk_a[2];
secp256k1_pubkey pk_b[2];
unsigned char pk_hash_a[32];
unsigned char pk_hash_b[32];
secp256k1_pubkey combined_pk_a;
secp256k1_pubkey combined_pk_b;
secp256k1_musig_session musig_session_a[2];
secp256k1_musig_session musig_session_b[2];
unsigned char noncommit_a[2][32];
unsigned char noncommit_b[2][32];
const unsigned char *noncommit_a_ptr[2];
const unsigned char *noncommit_b_ptr[2];
secp256k1_pubkey pubnon_a[2];
secp256k1_pubkey pubnon_b[2];
int nonce_is_negated_a;
int nonce_is_negated_b;
secp256k1_musig_session_signer_data data_a[2];
secp256k1_musig_session_signer_data data_b[2];
const unsigned char seed[32] = "still tired of choosing seeds...";
const unsigned char msg32_a[32] = "this is the message blockchain a";
const unsigned char msg32_b[32] = "this is the message blockchain b";
/* Step 1: key setup */
secp256k1_rand256(seckey_a[0]);
secp256k1_rand256(seckey_a[1]);
secp256k1_rand256(seckey_b[0]);
secp256k1_rand256(seckey_b[1]);
secp256k1_rand256(sec_adaptor);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[0], seckey_a[0]));
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[1], seckey_a[1]));
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[0], seckey_b[0]));
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[1], seckey_b[1]));
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, pk_hash_a, pk_a, 2));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, pk_hash_b, pk_b, 2));
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 0, seckey_a[0]));
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 1, seckey_a[1]));
noncommit_a_ptr[0] = noncommit_a[0];
noncommit_a_ptr[1] = noncommit_a[1];
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 0, seckey_b[0]));
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 1, seckey_b[1]));
noncommit_b_ptr[0] = noncommit_b[0];
noncommit_b_ptr[1] = noncommit_b[1];
/* Step 2: Exchange nonces */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, &pubnon_a[0], noncommit_a_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, &pubnon_a[1], noncommit_a_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, &pubnon_b[0], noncommit_b_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, &pubnon_b[1], noncommit_b_ptr, 2));
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], &pubnon_a[0]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], &pubnon_a[1]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], &pubnon_b[0]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[1], &pubnon_b[1]));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &nonce_is_negated_a, &pub_adaptor));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[1], data_a, 2, NULL, &pub_adaptor));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &nonce_is_negated_b, &pub_adaptor));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor));
/* Step 3: Signer 0 produces partial signatures for both chains. */
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[0], &partial_sig_a[0]));
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[0], &partial_sig_b[0]));
/* Step 4: Signer 1 receives partial signatures, verifies them and creates a
* partial signature to send B-coins to signer 0. */
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_a[1], data_a, &partial_sig_a[0], &pk_a[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_b[1], data_b, &partial_sig_b[0], &pk_b[0]) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[1], &partial_sig_b[1]));
/* Step 5: Signer 0 adapts its own partial signature and combines it with the
* partial signature from signer 1. This results in a complete signature which
* is broadcasted by signer 0 to take B-coins. */
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, nonce_is_negated_b));
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_b, msg32_b, &combined_pk_b) == 1);
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
* other partial signature, and takes A-coins. */
CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, &final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1);
CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, nonce_is_negated_a));
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_a, msg32_a, &combined_pk_a) == 1);
}
/* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the
* expected state. */
void sha256_tag_test(void) {
char tag[17] = "MuSig coefficient";
secp256k1_sha256 sha;
secp256k1_sha256 sha_tagged;
unsigned char buf[32];
unsigned char buf2[32];
size_t i;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, (unsigned char *) tag, 17);
secp256k1_sha256_finalize(&sha, buf);
/* buf = SHA256("MuSig coefficient") */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(&sha, buf, 32);
/* Is buffer fully consumed? */
CHECK((sha.bytes & 0x3F) == 0);
/* Compare with tagged SHA */
secp256k1_musig_sha256_init_tagged(&sha_tagged);
for (i = 0; i < 8; i++) {
CHECK(sha_tagged.s[i] == sha.s[i]);
}
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(&sha_tagged, buf, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_sha256_finalize(&sha_tagged, buf2);
CHECK(memcmp(buf, buf2, 32) == 0);
}
void run_musig_tests(void) {
int i;
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
musig_api_tests(scratch);
musig_state_machine_tests(scratch);
for (i = 0; i < count; i++) {
/* Run multiple times to ensure that the nonce is negated in some tests */
scriptless_atomic_swap(scratch);
}
sha256_tag_test();
secp256k1_scratch_space_destroy(scratch);
}
#endif

9
src/secp256k1/src/modules/schnorrsig/Makefile.am.include

@ -0,0 +1,9 @@
include_HEADERS += include/secp256k1_schnorrsig.h
noinst_HEADERS += src/modules/schnorrsig/main_impl.h
noinst_HEADERS += src/modules/schnorrsig/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_schnorrsig
bench_schnorrsig_SOURCES = src/bench_schnorrsig.c
bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif

339
src/secp256k1/src/modules/schnorrsig/main_impl.h

@ -0,0 +1,339 @@
/**********************************************************************
* Copyright (c) 2018 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_
#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_schnorrsig.h"
#include "hash.h"
int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig) {
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(out64 != NULL);
ARG_CHECK(sig != NULL);
memcpy(out64, sig->data, 64);
return 1;
}
int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64) {
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(in64 != NULL);
memcpy(sig->data, in64, 64);
return 1;
}
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, int *nonce_is_negated, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) {
secp256k1_scalar x;
secp256k1_scalar e;
secp256k1_scalar k;
secp256k1_gej pkj;
secp256k1_gej rj;
secp256k1_ge pk;
secp256k1_ge r;
secp256k1_sha256 sha;
int overflow;
unsigned char buf[33];
size_t buflen = sizeof(buf);
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(sig != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(seckey != NULL);
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_bipschnorr;
}
secp256k1_scalar_set_b32(&x, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (overflow || secp256k1_scalar_is_zero(&x)) {
memset(sig, 0, sizeof(*sig));
return 0;
}
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x);
secp256k1_ge_set_gej(&pk, &pkj);
if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) {
return 0;
}
secp256k1_scalar_set_b32(&k, buf, NULL);
if (secp256k1_scalar_is_zero(&k)) {
return 0;
}
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
secp256k1_ge_set_gej(&r, &rj);
if (nonce_is_negated != NULL) {
*nonce_is_negated = 0;
}
if (!secp256k1_fe_is_quad_var(&r.y)) {
secp256k1_scalar_negate(&k, &k);
if (nonce_is_negated != NULL) {
*nonce_is_negated = 1;
}
}
secp256k1_fe_normalize(&r.x);
secp256k1_fe_get_b32(&sig->data[0], &r.x);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, &sig->data[0], 32);
secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1);
secp256k1_sha256_write(&sha, buf, buflen);
secp256k1_sha256_write(&sha, msg32, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(&e, buf, NULL);
secp256k1_scalar_mul(&e, &e, &x);
secp256k1_scalar_add(&e, &e, &k);
secp256k1_scalar_get_b32(&sig->data[32], &e);
secp256k1_scalar_clear(&k);
secp256k1_scalar_clear(&x);
return 1;
}
/* Helper function for verification and batch verification.
* Computes R = sG - eP. */
static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_pubkey *pk) {
secp256k1_scalar nege;
secp256k1_ge pkp;
secp256k1_gej pkj;
secp256k1_scalar_negate(&nege, e);
if (!secp256k1_pubkey_load(ctx, &pkp, pk)) {
return 0;
}
secp256k1_gej_set_ge(&pkj, &pkp);
/* rj = s*G + (-e)*pkj */
secp256k1_ecmult(&ctx->ecmult_ctx, rj, &pkj, &nege, s);
return 1;
}
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk) {
secp256k1_scalar s;
secp256k1_scalar e;
secp256k1_gej rj;
secp256k1_fe rx;
secp256k1_sha256 sha;
unsigned char buf[33];
size_t buflen = sizeof(buf);
int overflow;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(sig != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(pk != NULL);
if (!secp256k1_fe_set_b32(&rx, &sig->data[0])) {
return 0;
}
secp256k1_scalar_set_b32(&s, &sig->data[32], &overflow);
if (overflow) {
return 0;
}
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, &sig->data[0], 32);
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(&sha, buf, buflen);
secp256k1_sha256_write(&sha, msg32, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(&e, buf, NULL);
if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pk)
|| !secp256k1_gej_has_quad_y_var(&rj) /* fails if rj is infinity */
|| !secp256k1_gej_eq_x_var(&rx, &rj)) {
return 0;
}
return 1;
}
/* Data that is used by the batch verification ecmult callback */
typedef struct {
const secp256k1_context *ctx;
/* Seed for the random number generator */
unsigned char chacha_seed[32];
/* Caches randomizers generated by the PRNG which returns two randomizers per call. Caching
* avoids having to call the PRNG twice as often. The very first randomizer will be set to 1 and
* the PRNG is called at every odd indexed schnorrsig to fill the cache. */
secp256k1_scalar randomizer_cache[2];
/* Signature, message, public key tuples to verify */
const secp256k1_schnorrsig *const *sig;
const unsigned char *const *msg32;
const secp256k1_pubkey *const *pk;
size_t n_sigs;
} secp256k1_schnorrsig_verify_ecmult_context;
/* Callback function which is called by ecmult_multi in order to convert the ecmult_context
* consisting of signature, message and public key tuples into scalars and points. */
static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_schnorrsig_verify_ecmult_context *ecmult_context = (secp256k1_schnorrsig_verify_ecmult_context *) data;
if (idx % 4 == 2) {
/* Every idx corresponds to a (scalar,point)-tuple. So this callback is called with 4
* consecutive tuples before we need to call the RNG for new randomizers:
* (-randomizer_cache[0], R1)
* (-randomizer_cache[0]*e1, P1)
* (-randomizer_cache[1], R2)
* (-randomizer_cache[1]*e2, P2) */
secp256k1_scalar_chacha20(&ecmult_context->randomizer_cache[0], &ecmult_context->randomizer_cache[1], ecmult_context->chacha_seed, idx / 4);
}
/* R */
if (idx % 2 == 0) {
secp256k1_fe rx;
*sc = ecmult_context->randomizer_cache[(idx / 2) % 2];
if (!secp256k1_fe_set_b32(&rx, &ecmult_context->sig[idx / 2]->data[0])) {
return 0;
}
if (!secp256k1_ge_set_xquad(pt, &rx)) {
return 0;
}
/* eP */
} else {
unsigned char buf[33];
size_t buflen = sizeof(buf);
secp256k1_sha256 sha;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32);
secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(&sha, buf, buflen);
secp256k1_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(sc, buf, NULL);
secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]);
if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) {
return 0;
}
}
return 1;
}
/** Helper function for batch verification. Hashes signature verification data into the
* randomization seed and initializes ecmult_context.
*
* Returns 1 if the randomizer was successfully initialized.
*
* Args: ctx: a secp256k1 context object
* Out: ecmult_context: context for batch_ecmult_callback
* In/Out sha: an initialized sha256 object which hashes the schnorrsig input in order to get a
* seed for the randomizer PRNG
* In: sig: array of signatures, or NULL if there are no signatures
* msg32: array of messages, or NULL if there are no signatures
* pk: array of public keys, or NULL if there are no signatures
* n_sigs: number of signatures in above arrays (must be 0 if they are NULL)
*/
int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) {
size_t i;
if (n_sigs > 0) {
ARG_CHECK(sig != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(pk != NULL);
}
for (i = 0; i < n_sigs; i++) {
unsigned char buf[33];
size_t buflen = sizeof(buf);
secp256k1_sha256_write(sha, sig[i]->data, 64);
secp256k1_sha256_write(sha, msg32[i], 32);
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(sha, buf, 32);
}
ecmult_context->ctx = ctx;
ecmult_context->sig = sig;
ecmult_context->msg32 = msg32;
ecmult_context->pk = pk;
ecmult_context->n_sigs = n_sigs;
return 1;
}
/** Helper function for batch verification. Sums the s part of all signatures multiplied by their
* randomizer.
*
* Returns 1 if s is successfully summed.
*
* In/Out: s: the s part of the input sigs is added to this s argument
* In: chacha_seed: PRNG seed for computing randomizers
* sig: array of signatures, or NULL if there are no signatures
* n_sigs: number of signatures in above array (must be 0 if they are NULL)
*/
int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) {
secp256k1_scalar randomizer_cache[2];
size_t i;
secp256k1_scalar_set_int(&randomizer_cache[0], 1);
for (i = 0; i < n_sigs; i++) {
int overflow;
secp256k1_scalar term;
if (i % 2 == 1) {
secp256k1_scalar_chacha20(&randomizer_cache[0], &randomizer_cache[1], chacha_seed, i / 2);
}
secp256k1_scalar_set_b32(&term, &sig[i]->data[32], &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_mul(&term, &term, &randomizer_cache[i % 2]);
secp256k1_scalar_add(s, s, &term);
}
return 1;
}
/* schnorrsig batch verification.
* Seeds a random number generator with the inputs and derives a random number ai for every
* signature i. Fails if y-coordinate of any R is not a quadratic residue or if
* 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */
int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) {
secp256k1_schnorrsig_verify_ecmult_context ecmult_context;
secp256k1_sha256 sha;
secp256k1_scalar s;
secp256k1_gej rj;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(scratch != NULL);
/* Check that n_sigs is less than half of the maximum size_t value. This is necessary because
* the number of points given to ecmult_multi is 2*n_sigs. */
ARG_CHECK(n_sigs <= SIZE_MAX / 2);
/* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit
* and 64-bit platforms. */
ARG_CHECK(n_sigs < (size_t)(1 << 31));
secp256k1_sha256_initialize(&sha);
if (!secp256k1_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) {
return 0;
}
secp256k1_sha256_finalize(&sha, ecmult_context.chacha_seed);
secp256k1_scalar_set_int(&ecmult_context.randomizer_cache[0], 1);
secp256k1_scalar_clear(&s);
if (!secp256k1_schnorrsig_verify_batch_sum_s(&s, ecmult_context.chacha_seed, sig, n_sigs)) {
return 0;
}
secp256k1_scalar_negate(&s, &s);
return secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs)
&& secp256k1_gej_is_infinity(&rj);
}
#endif

727
src/secp256k1/src/modules/schnorrsig/tests_impl.h

@ -0,0 +1,727 @@
/**********************************************************************
* Copyright (c) 2018 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_
#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_
#include "secp256k1_schnorrsig.h"
void test_schnorrsig_serialize(void) {
secp256k1_schnorrsig sig;
unsigned char in[64];
unsigned char out[64];
memset(in, 0x12, 64);
CHECK(secp256k1_schnorrsig_parse(ctx, &sig, in));
CHECK(secp256k1_schnorrsig_serialize(ctx, out, &sig));
CHECK(memcmp(in, out, 64) == 0);
}
void test_schnorrsig_api(secp256k1_scratch_space *scratch) {
unsigned char sk1[32];
unsigned char sk2[32];
unsigned char sk3[32];
unsigned char msg[32];
unsigned char sig64[64];
secp256k1_pubkey pk[3];
secp256k1_schnorrsig sig;
const secp256k1_schnorrsig *sigptr = &sig;
const unsigned char *msgptr = msg;
const secp256k1_pubkey *pkptr = &pk[0];
int nonce_is_negated;
/** setup **/
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
int ecount;
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_rand256(sk1);
secp256k1_rand256(sk2);
secp256k1_rand256(sk3);
secp256k1_rand256(msg);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk1) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk2) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[2], sk3) == 1);
/** main test body **/
ecount = 0;
CHECK(secp256k1_schnorrsig_sign(none, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign(vrfy, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign(sign, NULL, &nonce_is_negated, msg, sk1, NULL, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign(sign, &sig, NULL, msg, sk1, NULL, NULL) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, NULL, sk1, NULL, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, NULL, NULL, NULL) == 0);
CHECK(ecount == 5);
ecount = 0;
CHECK(secp256k1_schnorrsig_serialize(none, sig64, &sig) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_serialize(none, NULL, &sig) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_serialize(none, sig64, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_parse(none, &sig, sig64) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_parse(none, NULL, sig64) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_parse(none, &sig, NULL) == 0);
CHECK(ecount == 4);
ecount = 0;
CHECK(secp256k1_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_verify(sign, &sig, msg, &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, &pk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, NULL, &pk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, NULL) == 0);
CHECK(ecount == 5);
ecount = 0;
CHECK(secp256k1_schnorrsig_verify_batch(none, scratch, &sigptr, &msgptr, &pkptr, 1) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_verify_batch(sign, scratch, &sigptr, &msgptr, &pkptr, 1) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, NULL, NULL, 0) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, &msgptr, &pkptr, 1) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, NULL, &pkptr, 1) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, NULL, 1) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (size_t)1 << (sizeof(size_t)*8-1)) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1 << 31) == 0);
CHECK(ecount == 7);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(both);
}
/* Helper function for schnorrsig_bip_vectors
* Signs the message and checks that it's the same as expected_sig. */
void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig, const int expected_nonce_is_negated) {
secp256k1_schnorrsig sig;
unsigned char serialized_sig[64];
secp256k1_pubkey pk;
int nonce_is_negated;
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, &nonce_is_negated, msg, sk, NULL, NULL));
CHECK(nonce_is_negated == expected_nonce_is_negated);
CHECK(secp256k1_schnorrsig_serialize(ctx, serialized_sig, &sig));
CHECK(memcmp(serialized_sig, expected_sig, 64) == 0);
CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33));
CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &pk));
}
/* Helper function for schnorrsig_bip_vectors
* Checks that both verify and verify_batch return the same value as expected. */
void test_schnorrsig_bip_vectors_check_verify(secp256k1_scratch_space *scratch, const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig_serialized, int expected) {
const unsigned char *msg_arr[1];
const secp256k1_schnorrsig *sig_arr[1];
const secp256k1_pubkey *pk_arr[1];
secp256k1_pubkey pk;
secp256k1_schnorrsig sig;
CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33));
CHECK(secp256k1_schnorrsig_parse(ctx, &sig, sig_serialized));
sig_arr[0] = &sig;
msg_arr[0] = msg32;
pk_arr[0] = &pk;
CHECK(expected == secp256k1_schnorrsig_verify(ctx, &sig, msg32, &pk));
CHECK(expected == secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1));
}
/* Test vectors according to BIP-schnorr
* (https://github.com/sipa/bips/blob/7f6a73e53c8bbcf2d008ea0546f76433e22094a8/bip-schnorr/test-vectors.csv).
*/
void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) {
{
/* Test vector 1 */
const unsigned char sk1[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
};
const unsigned char pk1[33] = {
0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB,
0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B,
0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28,
0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17,
0x98
};
const unsigned char msg1[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const unsigned char sig1[64] = {
0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28,
0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2,
0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB,
0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6,
0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3,
0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84,
0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1,
0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05
};
test_schnorrsig_bip_vectors_check_signing(sk1, pk1, msg1, sig1, 1);
test_schnorrsig_bip_vectors_check_verify(scratch, pk1, msg1, sig1, 1);
}
{
/* Test vector 2 */
const unsigned char sk2[32] = {
0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A,
0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7,
0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56,
0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF
};
const unsigned char pk2[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg2[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig2[64] = {
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99,
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36,
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34,
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD
};
test_schnorrsig_bip_vectors_check_signing(sk2, pk2, msg2, sig2, 0);
test_schnorrsig_bip_vectors_check_verify(scratch, pk2, msg2, sig2, 1);
}
{
/* Test vector 3 */
const unsigned char sk3[32] = {
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC7
};
const unsigned char pk3[33] = {
0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09,
0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F,
0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D,
0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8,
0x4B
};
const unsigned char msg3[32] = {
0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A,
0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D,
0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33,
0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C
};
const unsigned char sig3[64] = {
0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F,
0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D,
0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53,
0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE,
0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93,
0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2,
0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60,
0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80
};
test_schnorrsig_bip_vectors_check_signing(sk3, pk3, msg3, sig3, 0);
test_schnorrsig_bip_vectors_check_verify(scratch, pk3, msg3, sig3, 1);
}
{
/* Test vector 4 */
const unsigned char pk4[33] = {
0x03, 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77,
0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF,
0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76,
0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A,
0x34
};
const unsigned char msg4[32] = {
0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2,
0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24,
0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B,
0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03
};
const unsigned char sig4[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F,
0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28,
0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63,
0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3,
0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3,
0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD,
0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk4, msg4, sig4, 1);
}
{
/* Test vector 5 */
const unsigned char pk5[33] = {
0x03, 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64,
0x40, 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05,
0x65, 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19,
0xFF, 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07,
0x8F
};
const unsigned char msg5[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const unsigned char sig5[64] = {
0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67,
0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B,
0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2,
0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35,
0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04,
0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34,
0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB,
0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk5, msg5, sig5, 1);
}
{
/* Test vector 6 */
const unsigned char pk6[33] = {
0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09,
0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F,
0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D,
0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8,
0x4B
};
const unsigned char msg6[32] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
const unsigned char sig6[64] = {
0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31,
0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1,
0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4,
0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC,
0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E,
0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F,
0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28,
0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk6, msg6, sig6, 1);
}
{
/* Test vector 7 */
const unsigned char pk7[33] = {
0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77,
0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF,
0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76,
0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A,
0x34
};
secp256k1_pubkey pk7_parsed;
/* No need to check the signature of the test vector as parsing the pubkey already fails */
CHECK(!secp256k1_ec_pubkey_parse(ctx, &pk7_parsed, pk7, 33));
}
{
/* Test vector 8 */
const unsigned char pk8[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg8[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig8[64] = {
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A,
0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46,
0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14,
0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk8, msg8, sig8, 0);
}
{
/* Test vector 9 */
const unsigned char pk9[33] = {
0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09,
0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F,
0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D,
0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8,
0x4B
};
const unsigned char msg9[32] = {
0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A,
0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D,
0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33,
0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C
};
const unsigned char sig9[64] = {
0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F,
0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D,
0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53,
0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE,
0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A,
0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D,
0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B,
0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk9, msg9, sig9, 0);
}
{
/* Test vector 10 */
const unsigned char pk10[33] = {
0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB,
0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B,
0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28,
0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17,
0x98
};
const unsigned char msg10[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const unsigned char sig10[64] = {
0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28,
0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2,
0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB,
0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6,
0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C,
0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A,
0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A,
0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk10, msg10, sig10, 0);
}
{
/* Test vector 11 */
const unsigned char pk11[33] = {
0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg11[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig11[64] = {
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99,
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36,
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34,
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk11, msg11, sig11, 0);
}
{
/* Test vector 12 */
const unsigned char pk12[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg12[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig12[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9E, 0x9D, 0x01, 0xAF, 0x98, 0x8B, 0x5C, 0xED,
0xCE, 0x47, 0x22, 0x1B, 0xFA, 0x9B, 0x22, 0x27,
0x21, 0xF3, 0xFA, 0x40, 0x89, 0x15, 0x44, 0x4A,
0x4B, 0x48, 0x90, 0x21, 0xDB, 0x55, 0x77, 0x5F
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk12, msg12, sig12, 0);
}
{
/* Test vector 13 */
const unsigned char pk13[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg13[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig13[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0xD3, 0x7D, 0xDF, 0x02, 0x54, 0x35, 0x18, 0x36,
0xD8, 0x4B, 0x1B, 0xD6, 0xA7, 0x95, 0xFD, 0x5D,
0x52, 0x30, 0x48, 0xF2, 0x98, 0xC4, 0x21, 0x4D,
0x18, 0x7F, 0xE4, 0x89, 0x29, 0x47, 0xF7, 0x28
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk13, msg13, sig13, 0);
}
{
/* Test vector 14 */
const unsigned char pk14[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg14[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig14[64] = {
0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99,
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36,
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34,
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk14, msg14, sig14, 0);
}
{
/* Test vector 15 */
const unsigned char pk15[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg15[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig15[64] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F,
0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99,
0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36,
0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34,
0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk15, msg15, sig15, 0);
}
{
/* Test vector 16 */
const unsigned char pk16[33] = {
0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C,
0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41,
0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE,
0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6,
0x59
};
const unsigned char msg16[32] = {
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
};
const unsigned char sig16[64] = {
0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
};
test_schnorrsig_bip_vectors_check_verify(scratch, pk16, msg16, sig16, 0);
}
}
/* Nonce function that returns constant 0 */
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
(void) msg32;
(void) key32;
(void) algo16;
(void) data;
(void) counter;
(void) nonce32;
return 0;
}
/* Nonce function that sets nonce to 0 */
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
(void) msg32;
(void) key32;
(void) algo16;
(void) data;
(void) counter;
memset(nonce32, 0, 32);
return 1;
}
void test_schnorrsig_sign(void) {
unsigned char sk[32];
const unsigned char msg[32] = "this is a msg for a schnorrsig..";
secp256k1_schnorrsig sig;
memset(sk, 23, sizeof(sk));
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, NULL, NULL) == 1);
/* Overflowing secret key */
memset(sk, 0xFF, sizeof(sk));
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, NULL, NULL) == 0);
memset(sk, 23, sizeof(sk));
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, nonce_function_failing, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, NULL, msg, sk, nonce_function_0, NULL) == 0);
}
#define N_SIGS 200
/* Creates N_SIGS valid signatures and verifies them with verify and verify_batch. Then flips some
* bits and checks that verification now fails. */
void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) {
const unsigned char sk[32] = "shhhhhhhh! this key is a secret.";
unsigned char msg[N_SIGS][32];
secp256k1_schnorrsig sig[N_SIGS];
size_t i;
const secp256k1_schnorrsig *sig_arr[N_SIGS];
const unsigned char *msg_arr[N_SIGS];
const secp256k1_pubkey *pk_arr[N_SIGS];
secp256k1_pubkey pk;
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk));
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, NULL, NULL, NULL, 0));
for (i = 0; i < N_SIGS; i++) {
secp256k1_rand256(msg[i]);
CHECK(secp256k1_schnorrsig_sign(ctx, &sig[i], NULL, msg[i], sk, NULL, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, &sig[i], msg[i], &pk));
sig_arr[i] = &sig[i];
msg_arr[i] = msg[i];
pk_arr[i] = &pk;
}
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1));
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 2));
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4));
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, N_SIGS));
{
/* Flip a few bits in the signature and in the message and check that
* verify and verify_batch fail */
size_t sig_idx = secp256k1_rand_int(4);
size_t byte_idx = secp256k1_rand_int(32);
unsigned char xorbyte = secp256k1_rand_int(254)+1;
sig[sig_idx].data[byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk));
CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4));
sig[sig_idx].data[byte_idx] ^= xorbyte;
byte_idx = secp256k1_rand_int(32);
sig[sig_idx].data[32+byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk));
CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4));
sig[sig_idx].data[32+byte_idx] ^= xorbyte;
byte_idx = secp256k1_rand_int(32);
msg[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk));
CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4));
msg[sig_idx][byte_idx] ^= xorbyte;
/* Check that above bitflips have been reversed correctly */
CHECK(secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk));
CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4));
}
}
#undef N_SIGS
void run_schnorrsig_tests(void) {
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
test_schnorrsig_serialize();
test_schnorrsig_api(scratch);
test_schnorrsig_bip_vectors(scratch);
test_schnorrsig_sign();
test_schnorrsig_sign_verify(scratch);
secp256k1_scratch_space_destroy(scratch);
}
#endif

118
src/secp256k1/src/scalar.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
@ -104,3 +106,119 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
#endif /* SECP256K1_SCALAR_H */
#else
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_H
#define SECP256K1_SCALAR_H
#include "num.h"
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low.h"
#elif defined(USE_SCALAR_4X64)
#include "scalar_4x64.h"
#elif defined(USE_SCALAR_8X32)
#include "scalar_8x32.h"
#else
#error "Please select scalar implementation"
#endif
/** Clear a scalar to prevent the leak of sensitive data. */
static void secp256k1_scalar_clear(secp256k1_scalar *r);
/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */
static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
/** Access bits from a scalar. Not constant time. */
static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
/** Set a scalar from a big endian byte array. */
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow);
/** Set a scalar to an unsigned integer. */
static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);
/** Set a scalar to an unsigned 64-bit integer */
static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v);
/** Convert a scalar to a byte array. */
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a);
/** Add two scalars together (modulo the group order). Returns whether it overflowed. */
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);
/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag);
/** Multiply two scalars (modulo the group order). */
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);
/** Shift a scalar right by some amount strictly between 0 and 16, returning
* the low bits that were shifted off */
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);
/** Compute the square of a scalar (modulo the group order). */
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Compute the inverse of a scalar (modulo the group order). */
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Compute the complement of a scalar (modulo the group order). */
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a);
/** Check whether a scalar equals zero. */
static int secp256k1_scalar_is_zero(const secp256k1_scalar *a);
/** Check whether a scalar equals one. */
static int secp256k1_scalar_is_one(const secp256k1_scalar *a);
/** Check whether a scalar, considered as an nonnegative integer, is even. */
static int secp256k1_scalar_is_even(const secp256k1_scalar *a);
/** Check whether a scalar is higher than the group order divided by 2. */
static int secp256k1_scalar_is_high(const secp256k1_scalar *a);
/** Conditionally negate a number, in constant time.
* Returns -1 if the number was negated, 1 otherwise */
static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag);
#ifndef USE_NUM_NONE
/** Convert a scalar to a number. */
static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a);
/** Get the order of the group as a number. */
static void secp256k1_scalar_order_get_num(secp256k1_num *r);
#endif
/** Compare two scalars. */
static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b);
#ifdef USE_ENDOMORPHISM
/** Find r1 and r2 such that r1+r2*2^128 = a. */
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a);
/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a);
#endif
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
/** Generate two scalars from a 32-byte seed and an integer using the chacha20 stream cipher */
void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx);
#endif /* SECP256K1_SCALAR_H */
#endif

25
src/secp256k1/src/scalar_4x64.h

@ -1,3 +1,26 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_REPR_H
#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef struct {
uint64_t d[4];
} secp256k1_scalar;
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}
#endif /* SECP256K1_SCALAR_REPR_H */
#else
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
@ -17,3 +40,5 @@ typedef struct {
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}
#endif /* SECP256K1_SCALAR_REPR_H */
#endif

1057
src/secp256k1/src/scalar_4x64_impl.h

File diff suppressed because it is too large

24
src/secp256k1/src/scalar_8x32.h

@ -1,3 +1,26 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_REPR_H
#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef struct {
uint32_t d[8];
} secp256k1_scalar;
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}
#endif /* SECP256K1_SCALAR_REPR_H */
#else
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
@ -17,3 +40,4 @@ typedef struct {
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}
#endif /* SECP256K1_SCALAR_REPR_H */
#endif

838
src/secp256k1/src/scalar_8x32_impl.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
@ -719,3 +721,839 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
}
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
#else
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H
#include <string.h>
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint32_t)0xD0364141UL)
#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL)
#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL)
#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL)
#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL)
#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL)
#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL)
#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL)
/* Limbs of 2^256 minus the secp256k1 order. */
#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1)
#define SECP256K1_N_C_1 (~SECP256K1_N_1)
#define SECP256K1_N_C_2 (~SECP256K1_N_2)
#define SECP256K1_N_C_3 (~SECP256K1_N_3)
#define SECP256K1_N_C_4 (1)
/* Limbs of half the secp256k1 order. */
#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL)
#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL)
#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL)
#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL)
#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL)
#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL)
#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL)
#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL)
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
r->d[0] = 0;
r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
r->d[4] = 0;
r->d[5] = 0;
r->d[6] = 0;
r->d[7] = 0;
}
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
r->d[0] = v;
r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
r->d[4] = 0;
r->d[5] = 0;
r->d[6] = 0;
r->d[7] = 0;
}
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) {
r->d[0] = v;
r->d[1] = v >> 32;
r->d[2] = 0;
r->d[3] = 0;
r->d[4] = 0;
r->d[5] = 0;
r->d[6] = 0;
r->d[7] = 0;
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
if ((offset + count - 1) >> 5 == offset >> 5) {
return secp256k1_scalar_get_bits(a, offset, count);
} else {
VERIFY_CHECK((offset >> 5) + 1 < 8);
return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1);
}
}
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */
no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */
no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */
no |= (a->d[4] < SECP256K1_N_4);
yes |= (a->d[4] > SECP256K1_N_4) & ~no;
no |= (a->d[3] < SECP256K1_N_3) & ~yes;
yes |= (a->d[3] > SECP256K1_N_3) & ~no;
no |= (a->d[2] < SECP256K1_N_2) & ~yes;
yes |= (a->d[2] > SECP256K1_N_2) & ~no;
no |= (a->d[1] < SECP256K1_N_1) & ~yes;
yes |= (a->d[1] > SECP256K1_N_1) & ~no;
yes |= (a->d[0] >= SECP256K1_N_0) & ~no;
return yes;
}
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) {
uint64_t t;
VERIFY_CHECK(overflow <= 1);
t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0;
r->d[0] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1;
r->d[1] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2;
r->d[2] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3;
r->d[3] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4;
r->d[4] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[5];
r->d[5] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[6];
r->d[6] = t & 0xFFFFFFFFUL; t >>= 32;
t += (uint64_t)r->d[7];
r->d[7] = t & 0xFFFFFFFFUL;
return overflow;
}
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
uint64_t t = (uint64_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[1] + b->d[1];
r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[2] + b->d[2];
r->d[2] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[3] + b->d[3];
r->d[3] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[4] + b->d[4];
r->d[4] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[5] + b->d[5];
r->d[5] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[6] + b->d[6];
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[7] + b->d[7];
r->d[7] = t & 0xFFFFFFFFULL; t >>= 32;
overflow = t + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint64_t t;
VERIFY_CHECK(bit < 256);
bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F));
r->d[2] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F));
r->d[3] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F));
r->d[4] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F));
r->d[5] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F));
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F));
r->d[7] = t & 0xFFFFFFFFULL;
#ifdef VERIFY
VERIFY_CHECK((t >> 32) == 0);
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;
r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;
r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24;
r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24;
r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24;
r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24;
r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24;
r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24;
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
}
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7];
bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6];
bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5];
bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4];
bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3];
bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2];
bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1];
bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
}
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0);
uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1;
r->d[0] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[1]) + SECP256K1_N_1;
r->d[1] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[2]) + SECP256K1_N_2;
r->d[2] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[3]) + SECP256K1_N_3;
r->d[3] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[4]) + SECP256K1_N_4;
r->d[4] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[5]) + SECP256K1_N_5;
r->d[5] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[6]) + SECP256K1_N_6;
r->d[6] = t & nonzero; t >>= 32;
t += (uint64_t)(~a->d[7]) + SECP256K1_N_7;
r->d[7] = t & nonzero;
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
}
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
int yes = 0;
int no = 0;
no |= (a->d[7] < SECP256K1_N_H_7);
yes |= (a->d[7] > SECP256K1_N_H_7) & ~no;
no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */
no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */
no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */
no |= (a->d[3] < SECP256K1_N_H_3) & ~yes;
yes |= (a->d[3] > SECP256K1_N_H_3) & ~no;
no |= (a->d[2] < SECP256K1_N_H_2) & ~yes;
yes |= (a->d[2] > SECP256K1_N_H_2) & ~no;
no |= (a->d[1] < SECP256K1_N_H_1) & ~yes;
yes |= (a->d[1] > SECP256K1_N_H_1) & ~no;
yes |= (a->d[0] > SECP256K1_N_H_0) & ~no;
return yes;
}
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
uint32_t mask = !flag - 1;
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
r->d[0] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
r->d[1] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);
r->d[2] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);
r->d[3] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask);
r->d[4] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask);
r->d[5] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask);
r->d[6] = t & nonzero; t >>= 32;
t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask);
r->d[7] = t & nonzero;
return 2 * (mask == 0) - 1;
}
/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */
/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd(a,b) { \
uint32_t tl, th; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
c1 += th; /* overflow is handled on the next line */ \
c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
}
/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */
#define muladd_fast(a,b) { \
uint32_t tl, th; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
c1 += th; /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK(c1 >= th); \
}
/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd2(a,b) { \
uint32_t tl, th, th2, tl2; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
c1 += th2; /* overflow is handled on the next line */ \
c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
}
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
over = (c0 < (a)) ? 1 : 0; \
c1 += over; /* overflow is handled on the next line */ \
c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \
}
/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
#define sumadd_fast(a) { \
c0 += (a); /* overflow is handled on the next line */ \
c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
VERIFY_CHECK(c2 == 0); \
}
/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */
#define extract(n) { \
(n) = c0; \
c0 = c1; \
c1 = c2; \
c2 = 0; \
}
/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */
#define extract_fast(n) { \
(n) = c0; \
c0 = c1; \
c1 = 0; \
VERIFY_CHECK(c2 == 0); \
}
static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) {
uint64_t c;
uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15];
uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12;
uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8;
/* 96 bit accumulator. */
uint32_t c0, c1, c2;
/* Reduce 512 bits into 385. */
/* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */
c0 = l[0]; c1 = 0; c2 = 0;
muladd_fast(n0, SECP256K1_N_C_0);
extract_fast(m0);
sumadd_fast(l[1]);
muladd(n1, SECP256K1_N_C_0);
muladd(n0, SECP256K1_N_C_1);
extract(m1);
sumadd(l[2]);
muladd(n2, SECP256K1_N_C_0);
muladd(n1, SECP256K1_N_C_1);
muladd(n0, SECP256K1_N_C_2);
extract(m2);
sumadd(l[3]);
muladd(n3, SECP256K1_N_C_0);
muladd(n2, SECP256K1_N_C_1);
muladd(n1, SECP256K1_N_C_2);
muladd(n0, SECP256K1_N_C_3);
extract(m3);
sumadd(l[4]);
muladd(n4, SECP256K1_N_C_0);
muladd(n3, SECP256K1_N_C_1);
muladd(n2, SECP256K1_N_C_2);
muladd(n1, SECP256K1_N_C_3);
sumadd(n0);
extract(m4);
sumadd(l[5]);
muladd(n5, SECP256K1_N_C_0);
muladd(n4, SECP256K1_N_C_1);
muladd(n3, SECP256K1_N_C_2);
muladd(n2, SECP256K1_N_C_3);
sumadd(n1);
extract(m5);
sumadd(l[6]);
muladd(n6, SECP256K1_N_C_0);
muladd(n5, SECP256K1_N_C_1);
muladd(n4, SECP256K1_N_C_2);
muladd(n3, SECP256K1_N_C_3);
sumadd(n2);
extract(m6);
sumadd(l[7]);
muladd(n7, SECP256K1_N_C_0);
muladd(n6, SECP256K1_N_C_1);
muladd(n5, SECP256K1_N_C_2);
muladd(n4, SECP256K1_N_C_3);
sumadd(n3);
extract(m7);
muladd(n7, SECP256K1_N_C_1);
muladd(n6, SECP256K1_N_C_2);
muladd(n5, SECP256K1_N_C_3);
sumadd(n4);
extract(m8);
muladd(n7, SECP256K1_N_C_2);
muladd(n6, SECP256K1_N_C_3);
sumadd(n5);
extract(m9);
muladd(n7, SECP256K1_N_C_3);
sumadd(n6);
extract(m10);
sumadd_fast(n7);
extract_fast(m11);
VERIFY_CHECK(c0 <= 1);
m12 = c0;
/* Reduce 385 bits into 258. */
/* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */
c0 = m0; c1 = 0; c2 = 0;
muladd_fast(m8, SECP256K1_N_C_0);
extract_fast(p0);
sumadd_fast(m1);
muladd(m9, SECP256K1_N_C_0);
muladd(m8, SECP256K1_N_C_1);
extract(p1);
sumadd(m2);
muladd(m10, SECP256K1_N_C_0);
muladd(m9, SECP256K1_N_C_1);
muladd(m8, SECP256K1_N_C_2);
extract(p2);
sumadd(m3);
muladd(m11, SECP256K1_N_C_0);
muladd(m10, SECP256K1_N_C_1);
muladd(m9, SECP256K1_N_C_2);
muladd(m8, SECP256K1_N_C_3);
extract(p3);
sumadd(m4);
muladd(m12, SECP256K1_N_C_0);
muladd(m11, SECP256K1_N_C_1);
muladd(m10, SECP256K1_N_C_2);
muladd(m9, SECP256K1_N_C_3);
sumadd(m8);
extract(p4);
sumadd(m5);
muladd(m12, SECP256K1_N_C_1);
muladd(m11, SECP256K1_N_C_2);
muladd(m10, SECP256K1_N_C_3);
sumadd(m9);
extract(p5);
sumadd(m6);
muladd(m12, SECP256K1_N_C_2);
muladd(m11, SECP256K1_N_C_3);
sumadd(m10);
extract(p6);
sumadd_fast(m7);
muladd_fast(m12, SECP256K1_N_C_3);
sumadd_fast(m11);
extract_fast(p7);
p8 = c0 + m12;
VERIFY_CHECK(p8 <= 2);
/* Reduce 258 bits into 256. */
/* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */
c = p0 + (uint64_t)SECP256K1_N_C_0 * p8;
r->d[0] = c & 0xFFFFFFFFUL; c >>= 32;
c += p1 + (uint64_t)SECP256K1_N_C_1 * p8;
r->d[1] = c & 0xFFFFFFFFUL; c >>= 32;
c += p2 + (uint64_t)SECP256K1_N_C_2 * p8;
r->d[2] = c & 0xFFFFFFFFUL; c >>= 32;
c += p3 + (uint64_t)SECP256K1_N_C_3 * p8;
r->d[3] = c & 0xFFFFFFFFUL; c >>= 32;
c += p4 + (uint64_t)p8;
r->d[4] = c & 0xFFFFFFFFUL; c >>= 32;
c += p5;
r->d[5] = c & 0xFFFFFFFFUL; c >>= 32;
c += p6;
r->d[6] = c & 0xFFFFFFFFUL; c >>= 32;
c += p7;
r->d[7] = c & 0xFFFFFFFFUL; c >>= 32;
/* Final reduction of r. */
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
/* l[0..15] = a[0..7] * b[0..7]. */
muladd_fast(a->d[0], b->d[0]);
extract_fast(l[0]);
muladd(a->d[0], b->d[1]);
muladd(a->d[1], b->d[0]);
extract(l[1]);
muladd(a->d[0], b->d[2]);
muladd(a->d[1], b->d[1]);
muladd(a->d[2], b->d[0]);
extract(l[2]);
muladd(a->d[0], b->d[3]);
muladd(a->d[1], b->d[2]);
muladd(a->d[2], b->d[1]);
muladd(a->d[3], b->d[0]);
extract(l[3]);
muladd(a->d[0], b->d[4]);
muladd(a->d[1], b->d[3]);
muladd(a->d[2], b->d[2]);
muladd(a->d[3], b->d[1]);
muladd(a->d[4], b->d[0]);
extract(l[4]);
muladd(a->d[0], b->d[5]);
muladd(a->d[1], b->d[4]);
muladd(a->d[2], b->d[3]);
muladd(a->d[3], b->d[2]);
muladd(a->d[4], b->d[1]);
muladd(a->d[5], b->d[0]);
extract(l[5]);
muladd(a->d[0], b->d[6]);
muladd(a->d[1], b->d[5]);
muladd(a->d[2], b->d[4]);
muladd(a->d[3], b->d[3]);
muladd(a->d[4], b->d[2]);
muladd(a->d[5], b->d[1]);
muladd(a->d[6], b->d[0]);
extract(l[6]);
muladd(a->d[0], b->d[7]);
muladd(a->d[1], b->d[6]);
muladd(a->d[2], b->d[5]);
muladd(a->d[3], b->d[4]);
muladd(a->d[4], b->d[3]);
muladd(a->d[5], b->d[2]);
muladd(a->d[6], b->d[1]);
muladd(a->d[7], b->d[0]);
extract(l[7]);
muladd(a->d[1], b->d[7]);
muladd(a->d[2], b->d[6]);
muladd(a->d[3], b->d[5]);
muladd(a->d[4], b->d[4]);
muladd(a->d[5], b->d[3]);
muladd(a->d[6], b->d[2]);
muladd(a->d[7], b->d[1]);
extract(l[8]);
muladd(a->d[2], b->d[7]);
muladd(a->d[3], b->d[6]);
muladd(a->d[4], b->d[5]);
muladd(a->d[5], b->d[4]);
muladd(a->d[6], b->d[3]);
muladd(a->d[7], b->d[2]);
extract(l[9]);
muladd(a->d[3], b->d[7]);
muladd(a->d[4], b->d[6]);
muladd(a->d[5], b->d[5]);
muladd(a->d[6], b->d[4]);
muladd(a->d[7], b->d[3]);
extract(l[10]);
muladd(a->d[4], b->d[7]);
muladd(a->d[5], b->d[6]);
muladd(a->d[6], b->d[5]);
muladd(a->d[7], b->d[4]);
extract(l[11]);
muladd(a->d[5], b->d[7]);
muladd(a->d[6], b->d[6]);
muladd(a->d[7], b->d[5]);
extract(l[12]);
muladd(a->d[6], b->d[7]);
muladd(a->d[7], b->d[6]);
extract(l[13]);
muladd_fast(a->d[7], b->d[7]);
extract_fast(l[14]);
VERIFY_CHECK(c1 == 0);
l[15] = c0;
}
static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) {
/* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0;
/* l[0..15] = a[0..7]^2. */
muladd_fast(a->d[0], a->d[0]);
extract_fast(l[0]);
muladd2(a->d[0], a->d[1]);
extract(l[1]);
muladd2(a->d[0], a->d[2]);
muladd(a->d[1], a->d[1]);
extract(l[2]);
muladd2(a->d[0], a->d[3]);
muladd2(a->d[1], a->d[2]);
extract(l[3]);
muladd2(a->d[0], a->d[4]);
muladd2(a->d[1], a->d[3]);
muladd(a->d[2], a->d[2]);
extract(l[4]);
muladd2(a->d[0], a->d[5]);
muladd2(a->d[1], a->d[4]);
muladd2(a->d[2], a->d[3]);
extract(l[5]);
muladd2(a->d[0], a->d[6]);
muladd2(a->d[1], a->d[5]);
muladd2(a->d[2], a->d[4]);
muladd(a->d[3], a->d[3]);
extract(l[6]);
muladd2(a->d[0], a->d[7]);
muladd2(a->d[1], a->d[6]);
muladd2(a->d[2], a->d[5]);
muladd2(a->d[3], a->d[4]);
extract(l[7]);
muladd2(a->d[1], a->d[7]);
muladd2(a->d[2], a->d[6]);
muladd2(a->d[3], a->d[5]);
muladd(a->d[4], a->d[4]);
extract(l[8]);
muladd2(a->d[2], a->d[7]);
muladd2(a->d[3], a->d[6]);
muladd2(a->d[4], a->d[5]);
extract(l[9]);
muladd2(a->d[3], a->d[7]);
muladd2(a->d[4], a->d[6]);
muladd(a->d[5], a->d[5]);
extract(l[10]);
muladd2(a->d[4], a->d[7]);
muladd2(a->d[5], a->d[6]);
extract(l[11]);
muladd2(a->d[5], a->d[7]);
muladd(a->d[6], a->d[6]);
extract(l[12]);
muladd2(a->d[6], a->d[7]);
extract(l[13]);
muladd_fast(a->d[7], a->d[7]);
extract_fast(l[14]);
VERIFY_CHECK(c1 == 0);
l[15] = c0;
}
#undef sumadd
#undef sumadd_fast
#undef muladd
#undef muladd_fast
#undef muladd2
#undef extract
#undef extract_fast
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
uint32_t l[16];
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
}
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
int ret;
VERIFY_CHECK(n > 0);
VERIFY_CHECK(n < 16);
ret = r->d[0] & ((1 << n) - 1);
r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n));
r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n));
r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n));
r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n));
r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n));
r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n));
r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n));
r->d[7] = (r->d[7] >> n);
return ret;
}
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint32_t l[16];
secp256k1_scalar_sqr_512(l, a);
secp256k1_scalar_reduce_512(r, l);
}
#ifdef USE_ENDOMORPHISM
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
r1->d[0] = a->d[0];
r1->d[1] = a->d[1];
r1->d[2] = a->d[2];
r1->d[3] = a->d[3];
r1->d[4] = 0;
r1->d[5] = 0;
r1->d[6] = 0;
r1->d[7] = 0;
r2->d[0] = a->d[4];
r2->d[1] = a->d[5];
r2->d[2] = a->d[6];
r2->d[3] = a->d[7];
r2->d[4] = 0;
r2->d[5] = 0;
r2->d[6] = 0;
r2->d[7] = 0;
}
#endif
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
}
SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) {
uint32_t l[16];
unsigned int shiftlimbs;
unsigned int shiftlow;
unsigned int shifthigh;
VERIFY_CHECK(shift >= 256);
secp256k1_scalar_mul_512(l, a, b);
shiftlimbs = shift >> 5;
shiftlow = shift & 0x1F;
shifthigh = 32 - shiftlow;
r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0;
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
}
#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n)))
#define QUARTERROUND(a,b,c,d) \
a += b; d = ROTL32(d ^ a, 16); \
c += d; b = ROTL32(b ^ c, 12); \
a += b; d = ROTL32(d ^ a, 8); \
c += d; b = ROTL32(b ^ c, 7);
#ifdef WORDS_BIGENDIAN
#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#define BE32(p) (p)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#define LE32(p) (p)
#endif
void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx) {
size_t n;
size_t over_count = 0;
uint32_t seed32[8];
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
int over1, over2;
memcpy((void *) seed32, (const void *) seed, 32);
do {
x0 = 0x61707865;
x1 = 0x3320646e;
x2 = 0x79622d32;
x3 = 0x6b206574;
x4 = LE32(seed32[0]);
x5 = LE32(seed32[1]);
x6 = LE32(seed32[2]);
x7 = LE32(seed32[3]);
x8 = LE32(seed32[4]);
x9 = LE32(seed32[5]);
x10 = LE32(seed32[6]);
x11 = LE32(seed32[7]);
x12 = idx;
x13 = idx >> 32;
x14 = 0;
x15 = over_count;
n = 10;
while (n--) {
QUARTERROUND(x0, x4, x8,x12)
QUARTERROUND(x1, x5, x9,x13)
QUARTERROUND(x2, x6,x10,x14)
QUARTERROUND(x3, x7,x11,x15)
QUARTERROUND(x0, x5,x10,x15)
QUARTERROUND(x1, x6,x11,x12)
QUARTERROUND(x2, x7, x8,x13)
QUARTERROUND(x3, x4, x9,x14)
}
x0 += 0x61707865;
x1 += 0x3320646e;
x2 += 0x79622d32;
x3 += 0x6b206574;
x4 += LE32(seed32[0]);
x5 += LE32(seed32[1]);
x6 += LE32(seed32[2]);
x7 += LE32(seed32[3]);
x8 += LE32(seed32[4]);
x9 += LE32(seed32[5]);
x10 += LE32(seed32[6]);
x11 += LE32(seed32[7]);
x12 += idx;
x13 += idx >> 32;
x14 += 0;
x15 += over_count;
r1->d[7] = LE32(x0);
r1->d[6] = LE32(x1);
r1->d[5] = LE32(x2);
r1->d[4] = LE32(x3);
r1->d[3] = LE32(x4);
r1->d[2] = LE32(x5);
r1->d[1] = LE32(x6);
r1->d[0] = LE32(x7);
r2->d[7] = LE32(x8);
r2->d[6] = LE32(x9);
r2->d[5] = LE32(x10);
r2->d[4] = LE32(x11);
r2->d[3] = LE32(x12);
r2->d[2] = LE32(x13);
r2->d[1] = LE32(x14);
r2->d[0] = LE32(x15);
over1 = secp256k1_scalar_check_overflow(r1);
over2 = secp256k1_scalar_check_overflow(r2);
over_count++;
} while (over1 | over2);
}
#undef ROTL32
#undef QUARTERROUND
#undef BE32
#undef LE32
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
#endif

340
src/secp256k1/src/scalar_impl.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
@ -331,3 +333,341 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
#endif
#endif /* SECP256K1_SCALAR_IMPL_H */
#else
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_IMPL_H
#define SECP256K1_SCALAR_IMPL_H
#include "group.h"
#include "scalar.h"
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low_impl.h"
#elif defined(USE_SCALAR_4X64)
#include "scalar_4x64_impl.h"
#elif defined(USE_SCALAR_8X32)
#include "scalar_8x32_impl.h"
#else
#error "Please select scalar implementation"
#endif
#ifndef USE_NUM_NONE
static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) {
unsigned char c[32];
secp256k1_scalar_get_b32(c, a);
secp256k1_num_set_bin(r, c, 32);
}
/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */
static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
#if defined(EXHAUSTIVE_TEST_ORDER)
static const unsigned char order[32] = {
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER
};
#else
static const unsigned char order[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
};
#endif
secp256k1_num_set_bin(r, order, 32);
}
#endif
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
#if defined(EXHAUSTIVE_TEST_ORDER)
int i;
*r = 0;
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
*r = i;
/* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
* have a composite group order; fix it in exhaustive_tests.c). */
VERIFY_CHECK(*r != 0);
}
#else
secp256k1_scalar *t;
int i;
/* First compute xN as x ^ (2^N - 1) for some values of N,
* and uM as x ^ M for some values of M. */
secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126;
secp256k1_scalar u2, u5, u9, u11, u13;
secp256k1_scalar_sqr(&u2, x);
secp256k1_scalar_mul(&x2, &u2, x);
secp256k1_scalar_mul(&u5, &u2, &x2);
secp256k1_scalar_mul(&x3, &u5, &u2);
secp256k1_scalar_mul(&u9, &x3, &u2);
secp256k1_scalar_mul(&u11, &u9, &u2);
secp256k1_scalar_mul(&u13, &u11, &u2);
secp256k1_scalar_sqr(&x6, &u13);
secp256k1_scalar_sqr(&x6, &x6);
secp256k1_scalar_mul(&x6, &x6, &u11);
secp256k1_scalar_sqr(&x8, &x6);
secp256k1_scalar_sqr(&x8, &x8);
secp256k1_scalar_mul(&x8, &x8, &x2);
secp256k1_scalar_sqr(&x14, &x8);
for (i = 0; i < 5; i++) {
secp256k1_scalar_sqr(&x14, &x14);
}
secp256k1_scalar_mul(&x14, &x14, &x6);
secp256k1_scalar_sqr(&x28, &x14);
for (i = 0; i < 13; i++) {
secp256k1_scalar_sqr(&x28, &x28);
}
secp256k1_scalar_mul(&x28, &x28, &x14);
secp256k1_scalar_sqr(&x56, &x28);
for (i = 0; i < 27; i++) {
secp256k1_scalar_sqr(&x56, &x56);
}
secp256k1_scalar_mul(&x56, &x56, &x28);
secp256k1_scalar_sqr(&x112, &x56);
for (i = 0; i < 55; i++) {
secp256k1_scalar_sqr(&x112, &x112);
}
secp256k1_scalar_mul(&x112, &x112, &x56);
secp256k1_scalar_sqr(&x126, &x112);
for (i = 0; i < 13; i++) {
secp256k1_scalar_sqr(&x126, &x126);
}
secp256k1_scalar_mul(&x126, &x126, &x14);
/* Then accumulate the final result (t starts at x126). */
t = &x126;
for (i = 0; i < 3; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u11); /* 1011 */
for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u11); /* 1011 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 5; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u13); /* 1101 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 3; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u9); /* 1001 */
for (i = 0; i < 6; i++) { /* 000 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 10; i++) { /* 0000000 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 9; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x8); /* 11111111 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u9); /* 1001 */
for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u11); /* 1011 */
for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u13); /* 1101 */
for (i = 0; i < 5; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x2); /* 11 */
for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u13); /* 1101 */
for (i = 0; i < 10; i++) { /* 000000 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u13); /* 1101 */
for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &u9); /* 1001 */
for (i = 0; i < 6; i++) { /* 00000 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, x); /* 1 */
for (i = 0; i < 8; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(r, t, &x6); /* 111111 */
}
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
return !(a->d[0] & 1);
}
#endif
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
#if defined(USE_SCALAR_INV_BUILTIN)
secp256k1_scalar_inverse(r, x);
#elif defined(USE_SCALAR_INV_NUM)
unsigned char b[32];
secp256k1_num n, m;
secp256k1_scalar t = *x;
secp256k1_scalar_get_b32(b, &t);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_scalar_order_get_num(&m);
secp256k1_num_mod_inverse(&n, &n, &m);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_scalar_set_b32(r, b, NULL);
/* Verify that the inverse was computed correctly, without GMP code. */
secp256k1_scalar_mul(&t, &t, r);
CHECK(secp256k1_scalar_is_one(&t));
#else
#error "Please select scalar inverse implementation"
#endif
}
#ifdef USE_ENDOMORPHISM
#if defined(EXHAUSTIVE_TEST_ORDER)
/**
* Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the
* full case we don't bother making k1 and k2 be small, we just want them to be
* nontrivial to get full test coverage for the exhaustive tests. We therefore
* (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda.
*/
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
*r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER;
*r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
}
#else
/**
* The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where
* lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
* 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72}
*
* "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm
* (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1
* and k2 have a small size.
* It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are:
*
* - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
* - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}
* - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}
* - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
*
* The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives
* k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and
* compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2.
*
* g1, g2 are precomputed constants used to replace division with a rounded multiplication
* when decomposing the scalar for an endomorphism-based point multiplication.
*
* The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
* Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
*
* The derivation is described in the paper "Efficient Software Implementation of Public-Key
* Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
* Section 4.3 (here we use a somewhat higher-precision estimate):
* d = a1*b2 - b1*a2
* g1 = round((2^272)*b2/d)
* g2 = round((2^272)*b1/d)
*
* (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
* as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
*
* The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order).
*/
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
secp256k1_scalar c1, c2;
static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST(
0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL,
0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL
);
static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL,
0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL
);
static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL
);
static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL,
0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL
);
static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL,
0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL
);
VERIFY_CHECK(r1 != a);
VERIFY_CHECK(r2 != a);
/* these _var calls are constant time since the shift amount is constant */
secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272);
secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272);
secp256k1_scalar_mul(&c1, &c1, &minus_b1);
secp256k1_scalar_mul(&c2, &c2, &minus_b2);
secp256k1_scalar_add(r2, &c1, &c2);
secp256k1_scalar_mul(r1, r2, &minus_lambda);
secp256k1_scalar_add(r1, r1, a);
}
#endif
#endif
#endif /* SECP256K1_SCALAR_IMPL_H */
#endif

20
src/secp256k1/src/scalar_low.h

@ -1,3 +1,22 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_REPR_H
#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef uint32_t secp256k1_scalar;
#endif /* SECP256K1_SCALAR_REPR_H */
#else
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
@ -13,3 +32,4 @@
typedef uint32_t secp256k1_scalar;
#endif /* SECP256K1_SCALAR_REPR_H */
#endif

126
src/secp256k1/src/scalar_low_impl.h

@ -1,3 +1,5 @@
#ifndef ENABLE_MODULE_MUSIG
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
@ -112,3 +114,127 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
}
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
#else
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H
#include "scalar.h"
#include <string.h>
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
return !(*a & 1);
}
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) { *r = v % EXHAUSTIVE_TEST_ORDER; }
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
if (offset < 32)
return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
else
return 0;
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
return secp256k1_scalar_get_bits(a, offset, count);
}
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
*r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
return *r < *b;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
if (flag && bit < 32)
*r += (1 << bit);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
#endif
}
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
const int base = 0x100 % EXHAUSTIVE_TEST_ORDER;
int i;
*r = 0;
for (i = 0; i < 32; i++) {
*r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER;
}
/* just deny overflow, it basically always happens */
if (overflow) *overflow = 0;
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
memset(bin, 0, 32);
bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
return *a == 0;
}
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
if (*a == 0) {
*r = 0;
} else {
*r = EXHAUSTIVE_TEST_ORDER - *a;
}
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
return *a == 1;
}
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
return *a > EXHAUSTIVE_TEST_ORDER / 2;
}
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
if (flag) secp256k1_scalar_negate(r, r);
return flag ? -1 : 1;
}
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
*r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
}
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
int ret;
VERIFY_CHECK(n > 0);
VERIFY_CHECK(n < 16);
ret = *r & ((1 << n) - 1);
*r >>= n;
return ret;
}
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
*r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
}
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
*r1 = *a;
*r2 = 0;
}
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
return *a == *b;
}
void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t n) {
*r1 = (seed[0] + n) % EXHAUSTIVE_TEST_ORDER;
*r2 = (seed[1] + n) % EXHAUSTIVE_TEST_ORDER;
}
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
#endif

40
src/secp256k1/src/scratch.h

@ -0,0 +1,40 @@
/**********************************************************************
* Copyright (c) 2017 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_SCRATCH_
#define _SECP256K1_SCRATCH_
#define SECP256K1_SCRATCH_MAX_FRAMES 5
/* The typedef is used internally; the struct name is used in the public API
* (where it is exposed as a different typedef) */
typedef struct secp256k1_scratch_space_struct {
void *data[SECP256K1_SCRATCH_MAX_FRAMES];
size_t offset[SECP256K1_SCRATCH_MAX_FRAMES];
size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES];
size_t frame;
size_t max_size;
const secp256k1_callback* error_callback;
} secp256k1_scratch;
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch);
/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects);
/** Deallocates a stack frame */
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch);
/** Returns the maximum allocation the scratch space will allow */
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects);
/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n);
#endif

87
src/secp256k1/src/scratch_impl.h

@ -0,0 +1,87 @@
/**********************************************************************
* Copyright (c) 2017 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_SCRATCH_IMPL_H_
#define _SECP256K1_SCRATCH_IMPL_H_
#include "scratch.h"
/* Using 16 bytes alignment because common architectures never have alignment
* requirements above 8 for any of the types we care about. In addition we
* leave some room because currently we don't care about a few bytes.
* TODO: Determine this at configure time. */
#define ALIGNMENT 16
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) {
secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret));
if (ret != NULL) {
memset(ret, 0, sizeof(*ret));
ret->max_size = max_size;
ret->error_callback = error_callback;
}
return ret;
}
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) {
if (scratch != NULL) {
VERIFY_CHECK(scratch->frame == 0);
free(scratch);
}
}
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) {
size_t i = 0;
size_t allocated = 0;
for (i = 0; i < scratch->frame; i++) {
allocated += scratch->frame_size[i];
}
if (scratch->max_size - allocated <= objects * ALIGNMENT) {
return 0;
}
return scratch->max_size - allocated - objects * ALIGNMENT;
}
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) {
VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES);
if (n <= secp256k1_scratch_max_allocation(scratch, objects)) {
n += objects * ALIGNMENT;
scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n);
if (scratch->data[scratch->frame] == NULL) {
return 0;
}
scratch->frame_size[scratch->frame] = n;
scratch->offset[scratch->frame] = 0;
scratch->frame++;
return 1;
} else {
return 0;
}
}
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) {
VERIFY_CHECK(scratch->frame > 0);
scratch->frame -= 1;
free(scratch->data[scratch->frame]);
}
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) {
void *ret;
size_t frame = scratch->frame - 1;
size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) {
return NULL;
}
ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]);
memset(ret, 0, size);
scratch->offset[frame] += size;
return ret;
}
#endif

31
src/secp256k1/src/secp256k1.c

@ -4,7 +4,7 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include "include/secp256k1.h"
#include "../include/secp256k1.h"
#include "util.h"
#include "num_impl.h"
@ -17,6 +17,7 @@
#include "ecdsa_impl.h"
#include "eckey_impl.h"
#include "hash_impl.h"
#include "scratch_impl.h"
#define ARG_CHECK(cond) do { \
if (EXPECT(!(cond), 0)) { \
@ -114,7 +115,7 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
ctx->error_callback.data = data;
}
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
if (sizeof(secp256k1_ge_storage) == 64) {
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
* representation inside secp256k1_pubkey, as conversion is very fast.
@ -133,7 +134,7 @@ static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge,
return 1;
}
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
if (sizeof(secp256k1_ge_storage) == 64) {
secp256k1_ge_storage s;
secp256k1_ge_to_storage(&s, ge);
@ -339,6 +340,27 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
return 1;
}
/* This nonce function is described in BIP-schnorr
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */
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) {
secp256k1_sha256 sha;
(void) data;
(void) counter;
VERIFY_CHECK(counter == 0);
/* Hash x||msg as per the spec */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, key32, 32);
secp256k1_sha256_write(&sha, msg32, 32);
/* Hash in algorithm, which is not in the spec, but may be critical to
* users depending on it to avoid nonce reuse across algorithms. */
if (algo16 != NULL) {
secp256k1_sha256_write(&sha, algo16, 16);
}
secp256k1_sha256_finalize(&sha, nonce32);
return 1;
}
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
@ -579,6 +601,9 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
# include "modules/ecdh/main_impl.h"
#endif
#include "../secp256k1/src/modules/schnorrsig/main_impl.h"
#include "../secp256k1/src/modules/musig/main_impl.h"
#ifdef ENABLE_MODULE_RECOVERY
# include "modules/recovery/main_impl.h"
#endif

18
src/secp256k1/src/tests.c

@ -2405,7 +2405,7 @@ void ecmult_const_random_mult(void) {
0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
);
secp256k1_gej b;
secp256k1_ecmult_const(&b, &a, &xn);
secp256k1_ecmult_const(&b, &a, &xn,256);
CHECK(secp256k1_ge_is_valid_var(&a));
ge_equals_gej(&expected_b, &b);
@ -2421,12 +2421,12 @@ void ecmult_const_commutativity(void) {
random_scalar_order_test(&a);
random_scalar_order_test(&b);
secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a,256);
secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b,256);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
secp256k1_ecmult_const(&res1, &mid1, &b);
secp256k1_ecmult_const(&res2, &mid2, &a);
secp256k1_ecmult_const(&res1, &mid1, &b,256);
secp256k1_ecmult_const(&res2, &mid2, &a,256);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
ge_equals_ge(&mid1, &mid2);
@ -2442,13 +2442,13 @@ void ecmult_const_mult_zero_one(void) {
secp256k1_scalar_negate(&negone, &one);
random_group_element_test(&point);
secp256k1_ecmult_const(&res1, &point, &zero);
secp256k1_ecmult_const(&res1, &point, &zero,256);
secp256k1_ge_set_gej(&res2, &res1);
CHECK(secp256k1_ge_is_infinity(&res2));
secp256k1_ecmult_const(&res1, &point, &one);
secp256k1_ecmult_const(&res1, &point, &one,256);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
secp256k1_ecmult_const(&res1, &point, &negone);
secp256k1_ecmult_const(&res1, &point, &negone,256);
secp256k1_gej_neg(&res1, &res1);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
@ -2474,7 +2474,7 @@ void ecmult_const_chain_multiply(void) {
for (i = 0; i < 100; ++i) {
secp256k1_ge tmp;
secp256k1_ge_set_gej(&tmp, &point);
secp256k1_ecmult_const(&point, &tmp, &scalar);
secp256k1_ecmult_const(&point, &tmp, &scalar,256);
}
secp256k1_ge_set_gej(&res, &point);
ge_equals_gej(&res, &expected_point);

2
src/secp256k1/src/tests_exhaustive.c

@ -174,7 +174,7 @@ void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *gr
ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
if (i > 0) {
secp256k1_ecmult_const(&tmp, &group[i], &ng);
secp256k1_ecmult_const(&tmp, &group[i], &ng,256);
ge_equals_gej(&group[(i * j) % order], &tmp);
}
}

0
src/uthash.h

0
src/utlist.h

7
src/wallet/rpcwallet.cpp

@ -5531,7 +5531,7 @@ UniValue cclibinfo(const UniValue& params, bool fHelp)
UniValue cclib(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; char *method; cJSON *jsonparams=0; uint8_t evalcode = EVAL_FIRSTUSER;
struct CCcontract_info *cp,C; char *method,*jsonstr=0; uint8_t evalcode = EVAL_FIRSTUSER;
if ( fHelp || params.size() > 3 )
throw runtime_error("cclib method [evalcode] [JSON params]\n");
if ( ASSETCHAINS_CCLIB.size() == 0 )
@ -5551,11 +5551,12 @@ UniValue cclib(const UniValue& params, bool fHelp)
}
if ( params.size() == 3 )
{
jsonparams = cJSON_Parse(params[2].get_str().c_str());
jsonstr = (char *)params[2].get_str().c_str();
//fprintf(stderr,"params.(%s %s %s)\n",params[0].get_str().c_str(),params[1].get_str().c_str(),jsonstr);
}
}
cp = CCinit(&C,evalcode);
return(CClib(cp,method,jsonparams));
return(CClib(cp,method,jsonstr));
}
UniValue oraclesaddress(const UniValue& params, bool fHelp)

9
zcutil/build-mac.sh

@ -47,14 +47,7 @@ make "$@" -C ./depends/ V=1 NO_QT=1 NO_PROTON=1
WD=$PWD
cd src/cc
echo $PWD
if make "$@"; then
echo CCLIB BUILD SUCCESSFUL
else
echo CCLIB BUILD FAILED
exit 1
fi
./makerogue
cd $WD
./autogen.sh

8
zcutil/build-win.sh

@ -1,5 +1,5 @@
#!/bin/bash
HOST=x86_64-w64-mingw32
export HOST=x86_64-w64-mingw32
CXX=x86_64-w64-mingw32-g++-posix
CC=x86_64-w64-mingw32-gcc-posix
PREFIX="$(pwd)/depends/$HOST"
@ -11,6 +11,12 @@ cd "$(dirname "$(readlink -f "$0")")/.."
cd depends/ && make HOST=$HOST V=1 NO_QT=1
cd ../
WD=$PWD
cd src/cc
echo $PWD
./makerogue
cd $WD
./autogen.sh
CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site CXXFLAGS="-DPTW32_STATIC_LIB -DCURL_STATICLIB -DCURVE_ALT_BN128 -fopenmp -pthread" ./configure --prefix="${PREFIX}" --host=x86_64-w64-mingw32 --enable-static --disable-shared
sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure

9
zcutil/build.sh

@ -106,14 +106,7 @@ CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure "$HARDENING_ARG"
WD=$PWD
cd src/cc
echo $PWD
if make "$@"; then
echo CCLIB BUILD SUCCESSFUL
else
echo CCLIB BUILD FAILED
exit 1
fi
./makerogue
cd $WD
"$MAKE" "$@" V=1

Loading…
Cancel
Save