diff --git a/.gitignore b/.gitignore index ce627b1f6..5ca85dd26 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ - -minerd -minerd.exe +minerd* +cpuminer +*.exe *.o +*.d +gmon.out autom4te.cache .deps @@ -29,3 +31,21 @@ mingw32-config.cache */.dirstamp *.iml + +*.vcxproj.user +*.opensdf +*.sdf +*.suo +Release/ +Debug/ +x64/Release/ +x64/Debug/ +*.pdb/ + +installer/ +res/cpuminer.aps +res/RC* +sign/ +sign.sh + +compat/curl-for-windows/ diff --git a/.travis.yml b/.travis.yml index 12ee67528..1f9f34961 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,14 @@ language: c compiler: - gcc +before_install: + - sudo apt-get update -qq + - sudo apt-get install libcurl4-openssl-dev + before_script: - ./autogen.sh script: - - ./configure - - make \ No newline at end of file + - ./configure --with-crypto --with-curl + - make + - ./cpuminer --cputest diff --git a/AUTHORS b/AUTHORS index 59d2e4492..3f705a7af 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,3 +13,5 @@ Neisklar prettyhatemachine LucasJones + +tpruvot@github diff --git a/Android.mk b/Android.mk new file mode 100644 index 000000000..45e64412e --- /dev/null +++ b/Android.mk @@ -0,0 +1,77 @@ +################################################################ +# Sample Android repo Makefile, used to test arm on the Tegra K1 +################################################################ + +cpuminer-src := $(call my-dir) + +LOCAL_PATH := $(cpuminer-src) +include $(CLEAR_VARS) + +LOCAL_MODULE=cpuminer-jansson +LOCAL_MODULE_TAGS=optional + +define all-c-files-under +$(patsubst ./%,%, \ + $(shell cd $(LOCAL_PATH) ; \ + find -L $(1) -name "*.c" -and -not -name ".*") \ + ) +endef + +LOCAL_SRC_FILES := $(call all-c-files-under,compat/jansson) +LOCAL_C_INCLUDES := $(cpuminer-src)/compat/jansson + +include $(BUILD_STATIC_LIBRARY) + +################################################################ + + +LOCAL_PATH := $(cpuminer-src) +include $(CLEAR_VARS) + +LOCAL_MODULE=cpuminer +LOCAL_MODULE_TAGS=optional +LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES +LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities +LOCAL_MODULE_STEM := $(LOCAL_MODULE) + +LOCAL_C_INCLUDES := $(cpuminer-src)/compat/bionic \ + $(cpuminer-src)/compat/jansson \ + $(TARGET_OUT_INTERMEDIATES)/include/libcurl \ + external/openssl/include \ + +LOCAL_CFLAGS := -std=c99 -Wno-pointer-sign -Wno-missing-field-initializers \ + -Wno-unused-parameter #-DNOASM +LOCAL_CFLAGS += -DVERSION=\"1.3\" + +sph_files:=$(call all-c-files-under,sha3) + +LOCAL_SRC_FILES=\ + cpu-miner.c util.c \ + api.c sysinfos.c \ + $(call all-c-files-under,algo) \ + $(filter-out sha3/md_helper.c,$(sph_files)) \ + $(call all-c-files-under,crypto) \ + $(call all-c-files-under,lyra2) \ + asm/sha2-$(TARGET_ARCH).S \ + asm/scrypt-$(TARGET_ARCH).S \ + asm/neoscrypt_asm.S + +LOCAL_STATIC_LIBRARIES := libm cpuminer-jansson +LOCAL_STATIC_LIBRARIES += libz libcrypto_static +LOCAL_STATIC_LIBRARIES += libssl_static + +# Require curl config changes and an addional +# module definition in external/curl(_static?) +#LOCAL_FORCE_STATIC_EXECUTABLE := true + +ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true) +LOCAL_CFLAGS += -DCURL_STATICLIB # -DHTTP_ONLY +LOCAL_STATIC_LIBRARIES += libcurl_static libc +else +LOCAL_SHARED_LIBRARIES := libssl libcrypto +LOCAL_SHARED_LIBRARIES += libcurl +#LOCAL_STATIC_LIBRARIES += libcurl_static +endif + +include $(BUILD_EXECUTABLE) + diff --git a/Dockerfile b/Dockerfile index dc2101ddf..8a68215c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,16 @@ -# -# Dockerfile for cpuminer -# usage: docker run creack/cpuminer --url xxxx --user xxxx --pass xxxx -# ex: docker run creack/cpuminer --url stratum+tcp://ltc.pool.com:80 --user creack.worker1 --pass abcdef -# -# +# Usage: docker build . +# Usage: docker run tpruvot/cpuminer-multi -a xevan --url=stratum+tcp://yiimp.ccminer.org:3739 --user=iGadPnKrdpW3pcdVC3aA77Ku4anrzJyaLG --pass=x -FROM ubuntu:12.10 -MAINTAINER Guillaume J. Charmes +FROM ubuntu:14.04 +MAINTAINER Tanguy Pruvot RUN apt-get update -qq -RUN apt-get install -qqy automake -RUN apt-get install -qqy libcurl4-openssl-dev -RUN apt-get install -qqy git -RUN apt-get install -qqy make +RUN apt-get install -qy automake autoconf pkg-config libcurl4-openssl-dev libssl-dev libjansson-dev libgmp-dev make g++ git -RUN git clone https://github.com/pooler/cpuminer +RUN git clone https://github.com/tpruvot/cpuminer-multi -b linux -RUN cd cpuminer && ./autogen.sh -RUN cd cpuminer && ./configure CFLAGS="-O3" -RUN cd cpuminer && make +RUN cd cpuminer-multi && ./build.sh -WORKDIR /cpuminer -ENTRYPOINT ["./minerd"] +WORKDIR /cpuminer-multi +ENTRYPOINT ["./cpuminer"] diff --git a/Makefile.am b/Makefile.am index b5687d37c..4398988cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,72 +9,164 @@ EXTRA_DIST = example-cfg.json nomacro.pl SUBDIRS = compat -INCLUDES = $(PTHREAD_FLAGS) -fno-strict-aliasing $(JANSSON_INCLUDES) - -bin_PROGRAMS = minerd - -dist_man_MANS = minerd.1 - -minerd_SOURCES = elist.h \ - miner.h \ - compat.h \ - cpu-miner.c \ - util.c \ - sha2.c \ - scrypt.c \ - keccak.c \ - heavy.c \ - quark.c \ - skein.c \ - ink.c \ - blake.c \ - cryptonight.c \ - fresh.c \ - x11.c \ - x13.c \ - x14.c \ - x15.c \ - sha3/sph_keccak.c \ - sha3/sph_hefty1.c \ - sha3/sph_groestl.c \ - sha3/sph_skein.c \ - sha3/sph_bmw.c \ - sha3/sph_jh.c \ - sha3/sph_shavite.c \ - sha3/sph_blake.c \ - sha3/sph_luffa.c \ - sha3/sph_cubehash.c \ - sha3/sph_simd.c \ - sha3/sph_echo.c \ - sha3/sph_hamsi.c \ - sha3/sph_fugue.c \ - sha3/sph_shabal.c \ - sha3/sph_whirlpool.c \ - crypto/oaes_lib.c \ - crypto/c_keccak.c \ - crypto/c_groestl.c \ - crypto/c_blake256.c \ - crypto/c_jh.c \ - crypto/c_skein.c \ - crypto/hash.c \ - crypto/aesb.c +ALL_INCLUDES = @PTHREAD_FLAGS@ -fno-strict-aliasing $(JANSSON_INCLUDES) -I. + +bin_PROGRAMS = cpuminer + +dist_man_MANS = cpuminer.1 + +cpuminer_SOURCES = \ + cpu-miner.c util.c \ + api.c sysinfos.c \ + uint256.cpp \ + sha3/sph_keccak.c \ + sha3/sph_hefty1.c \ + sha3/sph_groestl.c \ + sha3/sph_skein.c \ + sha3/sph_bmw.c \ + sha3/sph_jh.c \ + sha3/sph_shavite.c \ + sha3/sph_blake.c \ + sha3/mod_blakecoin.c \ + sha3/sph_luffa.c \ + sha3/sph_cubehash.c \ + sha3/sph_simd.c \ + sha3/sph_echo.c \ + sha3/sph_fugue.c \ + sha3/sph_hamsi.c \ + sha3/sph_haval.c \ + sha3/sph_panama.c \ + sha3/sph_radiogatun.c \ + sha3/sph_ripemd.c \ + sha3/sph_sha2.c \ + sha3/sph_sha2big.c \ + sha3/sph_shabal.c \ + sha3/sph_whirlpool.c \ + sha3/sph_tiger.c \ + sha3/gost_streebog.c \ + crypto/blake2s.c \ + crypto/blake2b.c \ + crypto/oaes_lib.c \ + crypto/c_keccak.c \ + crypto/c_groestl.c \ + crypto/c_blake256.c \ + crypto/c_jh.c \ + crypto/c_skein.c \ + crypto/hash.c \ + crypto/aesb.c \ + lyra2/Lyra2.c lyra2/Sponge.c \ + yescrypt/yescrypt-common.c yescrypt/yescrypt-best.c \ + yescrypt/sha256_Y.c \ + algo/allium.c \ + algo/axiom.c \ + algo/bastion.c \ + algo/blake.c \ + algo/blakecoin.c \ + algo/blake2.c \ + algo/bmw256.c \ + algo/c11.c \ + algo/cryptonight.c \ + algo/cryptolight.c \ + algo/decred.c \ + algo/drop.c \ + algo/fresh.c \ + algo/geek.c \ + algo/groestl.c \ + algo/heavy.c \ + algo/ink.c \ + algo/jha.c \ + algo/lbry.c \ + algo/luffa.c \ + algo/lyra2re.c \ + algo/lyra2rev2.c \ + algo/lyra2v3.c \ + algo/myr-groestl.c \ + algo/keccak.c \ + algo/pentablake.c \ + algo/phi1612.c \ + algo/phi2.c \ + algo/quark.c \ + algo/neoscrypt.c \ + algo/nist5.c \ + algo/pluck.c \ + algo/qubit.c \ + algo/rainforest.c \ + algo/scrypt.c \ + algo/scrypt-jane.c \ + algo/sha2.c \ + algo/sia.c \ + algo/sibcoin.c \ + algo/skein.c \ + algo/skein2.c \ + algo/sonoa.c \ + algo/s3.c \ + algo/bitcore.c \ + algo/timetravel.c \ + algo/tribus.c \ + algo/veltor.c \ + algo/x11evo.c \ + algo/x11.c \ + algo/x12.c \ + algo/x13.c \ + algo/x14.c \ + algo/x15.c \ + algo/x16r.c \ + algo/x16rv2.c \ + algo/x16s.c \ + algo/x20r.c \ + algo/x17.c \ + algo/xevan.c \ + algo/yescrypt.c \ + algo/zr5.c + +disable_flags = + if USE_ASM + cpuminer_SOURCES += asm/neoscrypt_asm.S if ARCH_x86 -minerd_SOURCES += sha2-x86.S scrypt-x86.S aesb-x86.S crypto/aesb-x86-impl.c + cpuminer_SOURCES += asm/sha2-x86.S asm/scrypt-x86.S asm/aesb-x86.S endif if ARCH_x86_64 -minerd_SOURCES += sha2-x64.S scrypt-x64.S aesb-x64.S + cpuminer_SOURCES += asm/sha2-x64.S asm/scrypt-x64.S asm/aesb-x64.S endif if ARCH_ARM -minerd_SOURCES += sha2-arm.S scrypt-arm.S + cpuminer_SOURCES += asm/sha2-arm.S asm/scrypt-arm.S endif +else + disable_flags += -DNOASM endif -minerd_LDFLAGS = $(PTHREAD_FLAGS) -minerd_LDADD = @LIBCURL@ @JANSSON_LIBS@ @PTHREAD_LIBS@ @WS2_LIBS@ -minerd_CPPFLAGS = @LIBCURL_CPPFLAGS@ -minerd_CFLAGS = -Ofast -flto -fuse-linker-plugin +if HAVE_WINDOWS + cpuminer_SOURCES += compat/winansi.c +endif + +cpuminer_LDFLAGS = @LDFLAGS@ +cpuminer_LDADD = @LIBCURL@ @JANSSON_LIBS@ @PTHREAD_LIBS@ @WS2_LIBS@ +cpuminer_CPPFLAGS = @LIBCURL_CPPFLAGS@ $(ALL_INCLUDES) +cpuminer_CFLAGS = -Wno-pointer-sign -Wno-pointer-to-int-cast $(disable_flags) if HAVE_WINDOWS -minerd_CFLAGS += -Wl,--stack,10485760 +cpuminer_CFLAGS += -Wl,--stack,10485760 +cpuminer_LDADD += -lcrypt32 -lgdi32 -lgcc -lgcc_eh +endif + +if ARCH_ARM +cpuminer_CFLAGS += -D__arm__ +endif + +if HAVE_WINDOWS +# use to profile an object +# gprof_cflags = -pg -g3 +# cpuminer_LDFLAGS += -pg +# cpuminer_CFLAGS += -fno-inline-functions -static + +# copy/paste from generated Makefile +common_ccflags = $(DEFS) $(ALL_INCLUDES) $(cpuminer_CPPFLAGS) $(CPPFLAGS) $(cpuminer_CFLAGS) $(CFLAGS) + +# special CFLAGS (if you find a simpler way to do that tell me ;) +cpuminer-neoscrypt.o: neoscrypt.c + @echo "CUSTOM ${@}: ${filter %.o,${^}} ${filter %.c,${^}}" + $(CC) $(common_ccflags) -g -O3 $(gprof_cflags) -MT $@ -MD -MP -c -o $@ $< + + endif diff --git a/NEWS b/NEWS index 0394812c9..f9c2f544d 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,116 @@ -Version multi 1.0.4 (Tanguy Pruvot) +Version 1.3.7 +- Add geek algo +- Add x16rv2 algo +- Add yescriptr8/16/32 variants + +Version 1.3.6 +- Add lyra2v3 algo +- Add blake2b algo +- Add x20r algo +- Add rainforest algo + +Version 1.3.5 +- Add allium algo +- Add x12 algo +- Add x16s algo +- Add phi and phi2 +- Add sonoa +- Handle new aeon cryptolight variant +- Handle new monero algo (hardcoded) + +Version 1.3.3 +- Add tribus algo +- Add x16r algo +- Add keccakc variant + +Version 1.3.2 +- Add bitcore algo +- Add jha algo + +Version 1.3.1 (Tanguy Pruvot) 26 Jan 2017 +- Add timetravel algo +- Add --max-log-rate to limit per-core logs + +Version 1.3 (Tanguy Pruvot) +- Add decred algo +- Add lbry algo +- Add sia algo +- Add x11evo algo +- Add x17 and xevan algos +- Add veltor algo +- Enhance Blake2-S +- Stratum benchmarks support +- Show diff and solved blocks by default + +Version 1.2 (Tanguy Pruvot) +- Add cryptonight-light (Aeon) +- Add Lyra2REv2 algo (Vertcoin) +- Allow to load a remote config with curl +- Algorithm parameter is now case insensitive +- Drop anime algo (dead coin) +- Add Sib(coin) algo +- Add Bastion algo +- Add Yescrypt and scrypt-jane algos +- Compute and show network diff in pools too +- Compute Shares diff and count solved blocks +- Checkup on arm, tested ok on Tegra K1 (CyanogenMod 12.1) + +version 1.1 (Tanguy Pruvot) +- Add basic API remote control (quit/seturl) +- Add GroestlCoin, Diamond and Myriad variants +- Add Pluck algo and fix gbt query crash +- Add ZR5 algo (ZRC) and fix longpoll bug on linux +- Add Luffa algo +- Add Skein2 algo (Double Skein for Woodcoin) +- Add Animecoin algo (Quark variant) +- Add Dropcoin pok algo +- Add BMW-256 (MDT) algo +- Add Axiom algo +- Change some logged strings +- Use all cores by default, not N-1 +- Handle a default config to run without params +- add cpu-priority and cpu-affinity options +- add NSIS installer script for windows setup +- Implement background option on windows +- add -m stratum option (diff-multiplier) +- Time limit to allow benchmarks or cron jobs +- Fix Cryptonight stratum support +- Allow to disable extranonce support + +version 1.0.9 (Tanguy Pruvot) +- pool extranonce subscribe +- upgrade jansson +- lyra2 algo +- fix for solo mining +- API websocket support + +Version 1.0.8 (Tanguy Pruvot) +- API Monitoring Support +- Enhance config values support (int/real/bool) +- Rewrite blake algo (speed x2) + +Version 1.0.7 (Tanguy Pruvot) +- Add NIST5 and QUBIT algos +- Show current stratum block height +- Fix wallet solo mining + +Version 1.0.6 (Tanguy Pruvot) +- Fix scrypt algo +- More work on VC2013 +- Add -f tuning option to test with reduced difficulty +- Add S3 algo + +Version 1.0.5 (Tanguy Pruvot) + +- Merge remaining v2.4 cpu-miner changes +- Add colored output (disable with --no-color) +- Test and fix blake on NEOS, needs 14 rounds (was 8) +- Add pentablake (5x blake256) (from bitbandi) +- Add neoscrypt +- Windows (VC++ 2013 and MinGW64 build support) +- Enhance --version informations (compiler + lib versions) + +Version 1.0.4 (Tanguy Pruvot) - Add x13 x14 and x15 algos (Sherlockcoin, X14Coin, Webcoin..) - Add scrypt:N variants (Vertcoin) @@ -20,6 +132,16 @@ Version multi 1.0.3 (Lucas Jones) - See README.md +Version 2.4 - May 20, 2014 + +- Add support for the getblocktemplate RPC method (BIP 22) +- Allow tunnelling Stratum through HTTP proxies +- Add a --no-redirect option to ignore redirection requests +- Timeout for long polling is now disabled by default +- Fix CPU affinity on Linux (kiyominer) +- Add support for building under 64-bit Cygwin +- Expand version information with build details + Version 2.3.3 - Feb 27, 2014 - The --url option is now mandatory @@ -241,7 +363,7 @@ Version 0.3.2 - December 23, 2010 Version 0.3.1 - December 19, 2010 - Critical fix for sha256_via -- Retry JSON-RPC failures (see --retry, under "minerd --help" output) +- Retry JSON-RPC failures (see --retry, under "--help" output) Version 0.3 - December 18, 2010 diff --git a/README.md b/README.md index 65a763207..315a84a83 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ CPUMiner-Multi ============== -[![Build Status](https://travis-ci.org/LucasJones/cpuminer-multi.svg?branch=master)](https://travis-ci.org/LucasJones/cpuminer-multi) +[![Build Status](https://travis-ci.org/tpruvot/cpuminer-multi.svg)](https://travis-ci.org/tpruvot/cpuminer-multi) This is a multi-threaded CPU miner, fork of [pooler](//github.com/pooler)'s cpuminer (see AUTHORS for list of contributors). @@ -20,73 +20,151 @@ fork of [pooler](//github.com/pooler)'s cpuminer (see AUTHORS for list of contri Algorithms ========== #### Currently supported - * ✓ __scrypt__ (Litecoin, Dogecoin, Feathercoin, etc..) - * ✓ __scrypt:N__ (Vertcoin [VTC]) - * ✓ __sha256d__ (Bitcoin, Freicoin, Peercoin/PPCoin, Terracoin, etc..) - * ✓ __x11__ (Darkcoin [DRK], Hirocoin, Limecoin) - * ✓ __x13__ (Sherlockcoin, [ACE], [B2B], [GRC], [XHC], etc..) + * ✓ __scrypt__ (Litecoin, Dogecoin, Feathercoin, ...) + * ✓ __scrypt:N__ + * ✓ __scrypt-jane:N__ + * ✓ __sha256d__ (Bitcoin, Freicoin, Peercoin/PPCoin, Terracoin, ...) + * ✓ __allium__ (Garlicoin, Tuxcoin) + * ✓ __axiom__ (Axiom Shabal-256 based MemoHash) + * ✓ __bastion__ (Joincoin [J]) + * ✓ __bitcore__ Permuted serie of 10 algos (BitCore) + * ✓ __blake__ (Saffron [SFR] Blake-256) + * ✓ __blake2s__ (NevaCoin Blake2-S 256) + * ✓ __blake2b__ (Not SIA one) + * ✓ __bmw__ (Midnight [MDT] BMW-256) + * ✓ __cryptonight__ (Bytecoin [BCN], Monero [XMR]) + * ✓ __cryptonight-light__ (Aeon) + * ✓ __decred__ (Blake256-14 [DCR]) + * ✓ __dmd-gr__ (Diamond-Groestl) + * ✓ __fresh__ (FreshCoin) + * ✓ __geek__ (GeekCash [GEEK]) + * ✓ __groestl__ (Groestlcoin) + * ✓ __jha__ (JackpotCoin, SweepStake) + * ✓ __lbry__ (LBRY Credits [LBC]) + * ✓ __lyra2RE__ (Cryptocoin) + * ✓ __lyra2REv2__ + * ✓ __lyra2REv3__ (VertCoin [VTC]) + * ✓ __myr-gr__ Myriad-Groestl (MyriadCoin [MYR]) + * ✓ __neoscrypt__ (Feathercoin) + * ✓ __nist5__ (MistCoin [MIC], TalkCoin [TAC], ...) + * ✓ __pentablake__ (Joincoin) + * ✓ __pluck__ (Supcoin [SUP]) + * ✓ __quark__ (Quarkcoin) + * ✓ __qubit__ (GeoCoin) + * ✓ __skein__ (Skeincoin, Myriadcoin, Xedoscoin, ...) + * ✓ __skein2__ (Woodcoin) + * ✓ __s3__ (OneCoin) + * ✓ __sia__ (Reversed Blake2B for SIA [SC]) + * ✓ __sib__ X11 + gost streebog (SibCoin) + * ✓ __timetravel__ Permuted serie of 8 algos (MachineCoin [MAC]) + * ✓ __tribus__ 3 of the top NIST5 algos (Denarius [DNR]) + * ✓ __vanilla__ (Blake-256 8-rounds - double sha256 [VNL]) + * ✓ __veltor__ (Veltor [VLT]) + * ✓ __xevan__ x17 x 2 on bigger header (BitSend [BSD]) + * ✓ __x11evo__ (Revolver [XRE]) + * ✓ __x11__ (Darkcoin [DRK], Hirocoin, Limecoin, ...) + * ✓ __x12__ (GalaxyCash [GCH]) + * ✓ __x13__ (Sherlockcoin, [ACE], [B2B], [GRC], [XHC], ...) * ✓ __x14__ (X14, Webcoin [WEB]) * ✓ __x15__ (RadianceCoin [RCE]) - * ✓ __cryptonight__ (Bytecoin [BCN], Monero) - * ✓ __fresh__ (FreshCoin) + * ✓ __x16r__ + * ✓ __x16rv2__ (Ravencoin [RVN], Trivechain [TRVC]) + * ✓ __x16s__ (Pigeoncoin [PGN]) + * ✓ __x17__ (Verge [XVG]) + * ✓ __x20r__ + * ✓ __yescrypt__ (GlobalBoostY [BSTY], Unitus [UIS], MyriadCoin [MYR]) + * ✓ __zr5__ (Ziftrcoin [ZRC]) #### Implemented, but untested - * ? keccak (Maxcoin HelixCoin, CryptoMeth, Galleon, 365coin, Slothcoin, BitcointalkCoin) * ? hefty1 (Heavycoin) - * ? quark (Quarkcoin) - * ? skein (Skeincoin, Myriadcoin) + * ? keccak (Maxcoin HelixCoin, CryptoMeth, Galleon, 365coin, Slothcoin, BitcointalkCoin) + * ? keccakc (Creativecoin) + * ? luffa (Joincoin, Doomcoin) + * ? rainforest * ? shavite3 (INKcoin) - * ? blake (Blakecoin) + * ? __yescryptr8__ __yescryptr16__ and __yescryptr32__ variants #### Planned support for * *scrypt-jane* (YaCoin, CopperBars, Pennies, Tickets, etc..) - * *qubit* (Qubitcoin, Myriadcoin) - * *groestl* (Groestlcoin) - + Dependencies ============ -* libcurl http://curl.haxx.se/libcurl/ -* jansson http://www.digip.org/jansson/ (jansson is included in-tree) -* openssl https://www.openssl.org/ + * libcurl http://curl.haxx.se/libcurl/ + * jansson http://www.digip.org/jansson/ (jansson source is included in-tree) + * openssl libcrypto https://www.openssl.org/ + * pthreads + * zlib (for curl/ssl) Download ======== -* Binary releases: https://github.com/LucasJones/cpuminer-multi/releases -* Git tree: https://github.com/LucasJones/cpuminer-multi - * Clone with `git clone https://github.com/LucasJones/cpuminer-multi` + * Windows releases: https://github.com/tpruvot/cpuminer-multi/releases + * Git tree: https://github.com/tpruvot/cpuminer-multi + * Clone with `git clone https://github.com/tpruvot/cpuminer-multi` Build ===== #### Basic *nix build instructions: - * ./autogen.sh # only needed if building from git repo - * ./nomacro.pl # only needed if building on Mac OS X or with Clang - * ./configure CFLAGS="*-march=native*" - * # Use -march=native if building for a single machine - * make + * just use `./build.sh` +_OR_ + +``` + ./autogen.sh # only needed if building from git repo + ./nomacro.pl # only needed if building on Mac OS X or with Clang + ./configure CFLAGS="*-march=native*" --with-crypto --with-curl + # Use -march=native if building for a single machine + make +``` + +#### Note for Debian/Ubuntu users: + +``` + apt-get install automake autoconf pkg-config libcurl4-openssl-dev libjansson-dev libssl-dev libgmp-dev zlib1g-dev make g++ +``` + +#### Note for OS X users: + +``` + brew install openssl curl + ./build.sh # if curl was installed to /usr/local/opt, else update build.sh paths in darwin section +``` + +#### Note for pi64 users: + +``` + ./autogen.sh + ./configure --disable-assembly CFLAGS="-Ofast -march=native" --with-crypto --with-curl +``` #### Notes for AIX users: * To build a 64-bit binary, export OBJECT_MODE=64 * GNU-style long options are not supported, but are accessible via configuration file -#### Basic Windows build instructions, using MinGW: - * Install MinGW and the MSYS Developer Tool Kit (http://www.mingw.org/) +#### Basic Windows build with Visual Studio 2013 + * All the required .lib files are now included in tree (windows only) + * AVX enabled by default for x64 platform (AVX2 and XOP could also be used) + +#### Basic Windows build instructions, using MinGW64: + * Install MinGW64 and the MSYS Developer Tool Kit (http://www.mingw.org/) * Make sure you have mstcpip.h in MinGW\include - * If using MinGW-w64, install pthreads-w64 + * install pthreads-w64 * Install libcurl devel (http://curl.haxx.se/download.html) * Make sure you have libcurl.m4 in MinGW\share\aclocal * Make sure you have curl-config in MinGW\bin * Install openssl devel (https://www.openssl.org/related/binaries.html) * In the MSYS shell, run: - * ./autogen.sh # only needed if building from git repo - * LIBCURL="-lcurldll" ./configure CFLAGS="*-march=native*" - * # Use -march=native if building for a single machine - * make + * for 64bit, you can use `./mingw64.sh` else : + `./autogen.sh # only needed if building from git repo` + ``` + LIBCURL="-lcurldll" ./configure CFLAGS="*-march=native*" + # Use -march=native if building for a single machine + make + ``` #### Architecture-specific notes: * ARM: * No runtime CPU detection. The miner can take advantage of some instructions specific to ARMv5E and later processors, but the decision whether to use them is made at compile time, based on compiler-defined macros. - * To use NEON instructions, add "-mfpu=neon" to CFLAGS. + * To use NEON instructions, add `-mfpu=neon` to CFLAGS. * x86: * The miner checks for SSE2 instructions support at runtime, and uses them if they are available. * x86-64: @@ -99,11 +177,11 @@ Build Usage instructions ================== -Run "minerd --help" to see options. +Run `cpuminer --help` to see options. ### Connecting through a proxy -Use the --proxy option. +Use the `--proxy` option. To use a SOCKS proxy, add a socks4:// or socks5:// prefix to the proxy host Protocols socks4a and socks5h, allowing remote name resolving, are also available since libcurl 7.18.0. @@ -113,14 +191,19 @@ When the --proxy option is not used, the program honors the http_proxy and all_p Donations ========= -Donations for the work done in this fork are accepted at +Donations for the work done in this fork are accepted : + +Tanguy Pruvot : +* BTC: `1FhDPLPpw18X4srecguG3MxJYe4a1JsZnd` + +Lucas Jones : * MRO: `472haywQKoxFzf7asaQ4XKBc2foAY4ezk8HiN63ifW4iAbJiLnfmJfhHSR9XmVKw2WYPnszJV9MEHj9Z5WMK9VCNHaGLDmJ` * BTC: `139QWoktddChHsZMWZFxmBva4FM96X2dhE` Credits ======= -CPUMiner-multi was forked from pooler's CPUMiner, and has been developed by Lucas Jones. -* [tpruvot](https://github.com/tpruvot) added some features and recent SHA3 based algorythmns +CPUMiner-multi was forked from pooler's CPUMiner, and has been started by Lucas Jones. +* [tpruvot](https://github.com/tpruvot) added all the recent features and newer algorythmns * [Wolf9466](https://github.com/wolf9466) helped with Intel AES-NI support for CryptoNight License diff --git a/algo/allium.c b/algo/allium.c new file mode 100644 index 000000000..df501738a --- /dev/null +++ b/algo/allium.c @@ -0,0 +1,93 @@ +/** + * Allium algo Implementation + */ + +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_groestl.h" + +#include "lyra2/Lyra2.h" + +#include "miner.h" + +void allium_hash(void *state, const void *input) +{ + uint32_t hashA[8], hashB[8]; + + sph_blake256_context ctx_blake; + sph_keccak256_context ctx_keccak; + sph_skein256_context ctx_skein; + sph_groestl256_context ctx_groestl; + sph_cubehash256_context ctx_cube; + + // sph_blake256_set_rounds(14); + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hashA); + + sph_keccak256_init(&ctx_keccak); + sph_keccak256(&ctx_keccak, hashA, 32); + sph_keccak256_close(&ctx_keccak, hashB); + + LYRA2(hashA, 32, hashB, 32, hashB, 32, 1, 8, 8); + + sph_cubehash256_init(&ctx_cube); + sph_cubehash256(&ctx_cube, hashA, 32); + sph_cubehash256_close(&ctx_cube, hashB); + + LYRA2(hashA, 32, hashB, 32, hashB, 32, 1, 8, 8); + + sph_skein256_init(&ctx_skein); + sph_skein256(&ctx_skein, hashA, 32); + sph_skein256_close(&ctx_skein, hashB); + + sph_groestl256_init(&ctx_groestl); + sph_groestl256(&ctx_groestl, hashB, 32); + sph_groestl256_close(&ctx_groestl, hashA); + + memcpy(state, hashA, 32); +} + +int scanhash_allium(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t n = first_nonce; + + if(opt_benchmark){ + ptarget[7] = 0x00ff; + } + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + allium_hash(hash, endiandata); + + if (hash[7] < Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/axiom.c b/algo/axiom.c new file mode 100644 index 000000000..bb5acd3a2 --- /dev/null +++ b/algo/axiom.c @@ -0,0 +1,79 @@ +#include "miner.h" + +#include +#include + +#include "sha3/sph_shabal.h" + +static __thread uint32_t _ALIGN(128) M[65536][8]; + +void axiomhash(void *output, const void *input) +{ + sph_shabal256_context ctx; + const int N = 65536; + + sph_shabal256_init(&ctx); + sph_shabal256(&ctx, input, 80); + sph_shabal256_close(&ctx, M[0]); + + for(int i = 1; i < N; i++) { + //sph_shabal256_init(&ctx); + sph_shabal256(&ctx, M[i-1], 32); + sph_shabal256_close(&ctx, M[i]); + } + + for(int b = 0; b < N; b++) + { + const int p = b > 0 ? b - 1 : 0xFFFF; + const int q = M[p][0] % 0xFFFF; + const int j = (b + q) % N; + + //sph_shabal256_init(&ctx); +#if 0 + sph_shabal256(&ctx, M[p], 32); + sph_shabal256(&ctx, M[j], 32); +#else + uint8_t _ALIGN(128) hash[64]; + memcpy(hash, M[p], 32); + memcpy(&hash[32], M[j], 32); + sph_shabal256(&ctx, hash, 64); +#endif + sph_shabal256_close(&ctx, M[b]); + } + memcpy(output, M[N-1], 32); +} + +int scanhash_axiom(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + axiomhash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/bastion.c b/algo/bastion.c new file mode 100644 index 000000000..96c34f904 --- /dev/null +++ b/algo/bastion.c @@ -0,0 +1,137 @@ +#include "miner.h" + +#include +#include +#include +#include +#include + +#include "sha3/sph_hefty1.h" + +#include "sha3/sph_luffa.h" +#include "sha3/sph_fugue.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_whirlpool.h" +#include "sha3/sph_shabal.h" +#include "sha3/sph_echo.h" +#include "sha3/sph_hamsi.h" + +void bastionhash(void *output, const void *input) +{ + unsigned char _ALIGN(128) hash[64] = { 0 }; + + sph_echo512_context ctx_echo; + sph_luffa512_context ctx_luffa; + sph_fugue512_context ctx_fugue; + sph_whirlpool_context ctx_whirlpool; + sph_shabal512_context ctx_shabal; + sph_skein512_context ctx_skein; + sph_hamsi512_context ctx_hamsi; + + HEFTY1(input, 80, hash); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + if (hash[0] & 0x8) + { + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + } else { + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + } + + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + if (hash[0] & 0x8) + { + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + } else { + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + } + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + if (hash[0] & 0x8) + { + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + } else { + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + } + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + if (hash[0] & 0x8) + { + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + } else { + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + } + + memcpy(output, hash, 32); +} + +int scanhash_bastion(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash32[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + bastionhash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/bitcore.c b/algo/bitcore.c new file mode 100644 index 000000000..b9f9e8132 --- /dev/null +++ b/algo/bitcore.c @@ -0,0 +1,217 @@ +/* + * Bitcore TimeTravel-10 Algo + * + * tpruvot 2017 + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// BitCore Genesis Timestamp +#define HASH_FUNC_BASE_TIMESTAMP 1492973331U + +#define HASH_FUNC_COUNT 10 +#define HASH_FUNC_COUNT_PERMUTATIONS 40320 + +static __thread uint32_t s_ntime = UINT32_MAX; +static __thread int permutation[HASH_FUNC_COUNT] = { 0 }; + +// helpers +static void swap(int *a, int *b) { + int c = *a; + *a = *b; + *b = c; +} + +static void reverse(int *pbegin, int *pend) { + while ( (pbegin != pend) && (pbegin != --pend) ) + swap(pbegin++, pend); +} + +static void next_permutation(int *pbegin, int *pend) { + if (pbegin == pend) + return; + + int *i = pbegin; + ++i; + if (i == pend) + return; + + i = pend; + --i; + + while (1) { + int *j = i; + --i; + + if (*i < *j) { + int *k = pend; + + while (!(*i < *--k)) + /* pass */; + + swap(i, k); + reverse(j, pend); + return; // true + } + + if (i == pbegin) { + reverse(pbegin, pend); + return; // false + } + } +} + +void bitcore_hash(void *output, const void *input) +{ + uint32_t _ALIGN(64) hash[16 * HASH_FUNC_COUNT]; + uint32_t *hashA, *hashB; + uint32_t dataLen = 64; + uint32_t *work_data = (uint32_t *)input; + const uint32_t timestamp = work_data[17]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + + // We want to permute algorithms. To get started we + // initialize an array with a sorted sequence of unique + // integers where every integer represents its own algorithm. + if (timestamp != s_ntime) { + int steps = (int) (timestamp - HASH_FUNC_BASE_TIMESTAMP) % HASH_FUNC_COUNT_PERMUTATIONS; + for (int i = 0; i < HASH_FUNC_COUNT; i++) { + permutation[i] = i; + } + for (int i = 0; i < steps; i++) { + next_permutation(permutation, permutation + HASH_FUNC_COUNT); + } + s_ntime = timestamp; + } + + for (int i = 0; i < HASH_FUNC_COUNT; i++) { + if (i == 0) { + dataLen = 80; + hashA = work_data; + } else { + dataLen = 64; + hashA = &hash[16 * (i - 1)]; + } + hashB = &hash[16 * i]; + + switch(permutation[i]) { + case 0: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, hashA, dataLen); + sph_blake512_close(&ctx_blake, hashB); + break; + case 1: + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hashA, dataLen); + sph_bmw512_close(&ctx_bmw, hashB); + break; + case 2: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hashA, dataLen); + sph_groestl512_close(&ctx_groestl, hashB); + break; + case 3: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hashA, dataLen); + sph_skein512_close(&ctx_skein, hashB); + break; + case 4: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hashA, dataLen); + sph_jh512_close(&ctx_jh, hashB); + break; + case 5: + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hashA, dataLen); + sph_keccak512_close(&ctx_keccak, hashB); + break; + case 6: + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hashA, dataLen); + sph_luffa512_close(&ctx_luffa, hashB); + break; + case 7: + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hashA, dataLen); + sph_cubehash512_close(&ctx_cubehash, hashB); + break; + case 8: + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hashA, dataLen); + sph_shavite512_close(&ctx_shavite, hashB); + break; + case 9: + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hashA, dataLen); + sph_simd512_close(&ctx_simd, hashB); + break; + default: + break; + } + } + + memcpy(output, &hash[16 * (HASH_FUNC_COUNT - 1)], 32); +} + +int scanhash_bitcore(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + bitcore_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/blake.c b/algo/blake.c new file mode 100644 index 000000000..ae697ef46 --- /dev/null +++ b/algo/blake.c @@ -0,0 +1,71 @@ +#include "miner.h" + +#include "sha3/sph_blake.h" + +#include +#include +#include + +static __thread sph_blake256_context blake_mid; +static __thread bool ctx_midstate_done = false; + +void blakehash(void *state, const void *input) +{ + sph_blake256_context ctx; + + uint8_t *ending = (uint8_t*) input; + ending += 64; + + // do one memcopy to get a fresh context + if (!ctx_midstate_done) { + sph_blake256_init(&blake_mid); + sph_blake256(&blake_mid, input, 64); + ctx_midstate_done = true; + } + memcpy(&ctx, &blake_mid, sizeof(blake_mid)); + + sph_blake256(&ctx, ending, 16); + sph_blake256_close(&ctx, state); +} + +int scanhash_blake(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t first_nonce = pdata[19]; + const uint32_t HTarget = opt_benchmark ? 0x7f : ptarget[7]; + + uint32_t n = first_nonce; + + ctx_midstate_done = false; + + // we need big endian data... + for (int kk=0; kk < 19; kk++) { + be32enc(&endiandata[kk], pdata[kk]); + } + +#ifdef DEBUG_ALGO + applog(LOG_DEBUG,"[%d] Target=%08x %08x", thr_id, ptarget[6], ptarget[7]); +#endif + + do { + be32enc(&endiandata[19], n); + blakehash(hash32, endiandata); + + if (hash32[7] <= HTarget && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + + n++; pdata[19] = n; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/blake2.c b/algo/blake2.c new file mode 100644 index 000000000..e04502592 --- /dev/null +++ b/algo/blake2.c @@ -0,0 +1,78 @@ +/** + * Blake2-S Implementation + * tpruvot@github 2015-2016 + */ + +#include "miner.h" + +#include +#include + +#include "crypto/blake2s.h" + +static __thread blake2s_state s_midstate; +static __thread blake2s_state s_ctx; +#define MIDLEN 76 +#define A 64 + +void blake2s_hash(void *output, const void *input) +{ + uint8_t _ALIGN(A) hash[BLAKE2S_OUTBYTES]; + blake2s_state blake2_ctx; + + blake2s_init(&blake2_ctx, BLAKE2S_OUTBYTES); + blake2s_update(&blake2_ctx, input, 80); + blake2s_final(&blake2_ctx, hash, BLAKE2S_OUTBYTES); + + memcpy(output, hash, 32); +} + +static void blake2s_hash_end(uint32_t *output, const uint32_t *input) +{ + s_ctx.buflen = MIDLEN; + memcpy(&s_ctx, &s_midstate, 32 + 16 + MIDLEN); + blake2s_update(&s_ctx, (uint8_t*) &input[MIDLEN/4], 80 - MIDLEN); + blake2s_final(&s_ctx, (uint8_t*) output, BLAKE2S_OUTBYTES); +} + +int scanhash_blake2s(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(A) vhashcpu[8]; + uint32_t _ALIGN(A) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + // midstate + blake2s_init(&s_midstate, BLAKE2S_OUTBYTES); + blake2s_update(&s_midstate, (uint8_t*) endiandata, MIDLEN); + memcpy(&s_ctx, &s_midstate, sizeof(blake2s_state)); + + do { + be32enc(&endiandata[19], n); + blake2s_hash_end(vhashcpu, endiandata); + + //blake2s_hash(vhashcpu, endiandata); + if (vhashcpu[7] < Htarg && fulltest(vhashcpu, ptarget)) { + work_set_target_ratio(work, vhashcpu); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/blake2b.c b/algo/blake2b.c new file mode 100644 index 000000000..e69de29bb diff --git a/algo/blakecoin.c b/algo/blakecoin.c new file mode 100644 index 000000000..cdd505b43 --- /dev/null +++ b/algo/blakecoin.c @@ -0,0 +1,75 @@ +#include "miner.h" + +#define BLAKE32_ROUNDS 8 +#include "sha3/sph_blake.h" + +void blakecoin_init(void *cc); +void blakecoin(void *cc, const void *data, size_t len); +void blakecoin_close(void *cc, void *dst); + +#include +#include +#include + +static __thread sph_blake256_context blake_mid; +static __thread bool ctx_midstate_done = false; + +void blakecoinhash(void *state, const void *input) +{ + sph_blake256_context ctx; + + uint8_t *ending = (uint8_t*) input; + ending += 64; + + // do one memcopy to get a fresh context + if (!ctx_midstate_done) { + blakecoin_init(&blake_mid); + blakecoin(&blake_mid, input, 64); + ctx_midstate_done = true; + } + memcpy(&ctx, &blake_mid, sizeof(blake_mid)); + + blakecoin(&ctx, ending, 16); + blakecoin_close(&ctx, state); +} + +int scanhash_blakecoin(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t first_nonce = pdata[19]; + const uint32_t HTarget = opt_benchmark ? 0x7f : ptarget[7]; + uint32_t n = first_nonce; + + ctx_midstate_done = false; + + // we need big endian data... + for (int kk=0; kk < 19; kk++) { + be32enc(&endiandata[kk], pdata[kk]); + } + +#ifdef DEBUG_ALGO + applog(LOG_DEBUG,"[%d] Target=%08x %08x", thr_id, ptarget[6], ptarget[7]); +#endif + + do { + be32enc(&endiandata[19], n); + blakecoinhash(hash32, endiandata); + + if (hash32[7] <= HTarget && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + + n++; pdata[19] = n; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/bmw256.c b/algo/bmw256.c new file mode 100644 index 000000000..d66d8a1e9 --- /dev/null +++ b/algo/bmw256.c @@ -0,0 +1,53 @@ +#include "miner.h" + +#include +#include + +#include "sha3/sph_bmw.h" + +void bmwhash(void *output, const void *input) +{ + uint32_t hash[16]; + sph_bmw256_context ctx; + + sph_bmw256_init(&ctx); + sph_bmw256(&ctx, input, 80); + sph_bmw256_close(&ctx, hash); + + memcpy(output, hash, 32); +} + +int scanhash_bmw(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + }; + + do { + be32enc(&endiandata[19], n); + bmwhash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/c11.c b/algo/c11.c new file mode 100644 index 000000000..62eff7a41 --- /dev/null +++ b/algo/c11.c @@ -0,0 +1,120 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_luffa.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" + + +void c11hash(void *output, const void *input) +{ + uint32_t _ALIGN(64) hash[16]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + + sph_blake512_init(&ctx_blake); + sph_blake512 (&ctx_blake, input, 80); + sph_blake512_close (&ctx_blake, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512 (&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512 (&ctx_skein, hash, 64); + sph_skein512_close (&ctx_skein, hash); + + sph_luffa512_init (&ctx_luffa1); + sph_luffa512 (&ctx_luffa1, hash, 64); + sph_luffa512_close (&ctx_luffa1, hash); + + sph_cubehash512_init (&ctx_cubehash1); + sph_cubehash512 (&ctx_cubehash1, hash, 64); + sph_cubehash512_close(&ctx_cubehash1, hash); + + sph_shavite512_init (&ctx_shavite1); + sph_shavite512 (&ctx_shavite1, hash, 64); + sph_shavite512_close(&ctx_shavite1, hash); + + sph_simd512_init (&ctx_simd1); + sph_simd512 (&ctx_simd1, hash, 64); + sph_simd512_close(&ctx_simd1, hash); + + sph_echo512_init (&ctx_echo1); + sph_echo512 (&ctx_echo1, hash, 64); + sph_echo512_close(&ctx_echo1, hash); + + memcpy(output, hash, 32); +} + +int scanhash_c11(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + c11hash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/cryptonight.c b/algo/cryptolight.c similarity index 73% rename from cryptonight.c rename to algo/cryptolight.c index 43bcef7df..6c39b9bf6 100644 --- a/cryptonight.c +++ b/algo/cryptolight.c @@ -2,10 +2,14 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -// Modified for CPUminer by Lucas Jones - -#include "cpuminer-config.h" #include "miner.h" + +#if defined(__arm__) || defined(_MSC_VER) +#ifndef NOASM +#define NOASM +#endif +#endif + #include "crypto/oaes_lib.h" #include "crypto/c_keccak.h" #include "crypto/c_groestl.h" @@ -19,14 +23,25 @@ #if __GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ < 6 typedef unsigned int uint128_t __attribute__ ((__mode__ (TI))); +#elif defined (_MSC_VER) +/* only for mingw64 on windows */ +#undef USE_INT128 +#define USE_INT128 (0) #else typedef __uint128_t uint128_t; #endif #endif -#define MEMORY (1 << 21) /* 2 MiB */ -#define ITER (1 << 20) +#define LITE 1 +#if LITE /* cryptonight-light */ +#define MEMORY (1 << 20) +#define ITER (1 << 19) +#else +#define MEMORY (1 << 21) /* 2 MiB */ +#define ITER (1 << 20) +#endif + #define AES_BLOCK_SIZE 16 #define AES_KEY_SIZE 32 /*16*/ #define INIT_SIZE_BLK 8 @@ -46,7 +61,7 @@ static void do_blake_hash(const void* input, size_t len, char* output) { blake256_hash((uint8_t*)output, input, len); } -void do_groestl_hash(const void* input, size_t len, char* output) { +static void do_groestl_hash(const void* input, size_t len, char* output) { groestl(input, len * 8, (uint8_t*)output); } @@ -60,28 +75,67 @@ static void do_skein_hash(const void* input, size_t len, char* output) { assert(likely(SKEIN_SUCCESS == r)); } -extern int fast_aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); extern int aesb_pseudo_round_mut(uint8_t *val, uint8_t *expandedKey); +#if !defined(_MSC_VER) && !defined(NOASM) +extern int fast_aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); extern int fast_aesb_pseudo_round_mut(uint8_t *val, uint8_t *expandedKey); +#else +#define fast_aesb_single_round aesb_single_round +#define fast_aesb_pseudo_round_mut aesb_pseudo_round_mut +#endif + +#if defined(NOASM) || !defined(__x86_64__) +static uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} +#else +extern uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi); +#endif static void (* const extra_hashes[4])(const void *, size_t, char *) = { do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash }; -// Credit to Wolf for optimizing this function + static inline size_t e2i(const uint8_t* a) { +#if !LITE return ((uint32_t *)a)[0] & 0x1FFFF0; +#else + return ((uint32_t *)a)[0] & 0xFFFF0; +#endif } -static inline void mul_sum_xor_dst(const uint8_t* a, uint8_t* c, uint8_t* dst) { +static inline void mul_sum_xor_dst(const uint8_t* a, uint8_t* c, uint8_t* dst, const int variant, const uint64_t tweak) { uint64_t hi, lo = mul128(((uint64_t*) a)[0], ((uint64_t*) dst)[0], &hi) + ((uint64_t*) c)[1]; hi += ((uint64_t*) c)[0]; ((uint64_t*) c)[0] = ((uint64_t*) dst)[0] ^ hi; ((uint64_t*) c)[1] = ((uint64_t*) dst)[1] ^ lo; ((uint64_t*) dst)[0] = hi; - ((uint64_t*) dst)[1] = lo; + ((uint64_t*) dst)[1] = variant ? lo ^ tweak : lo; } static inline void xor_blocks(uint8_t* a, const uint8_t* b) { @@ -102,22 +156,35 @@ static inline void xor_blocks_dst(const uint8_t* a, const uint8_t* b, uint8_t* d #endif } +static void cryptolight_store_variant(void* state, int variant) { + if (variant == 1) { + // use variant 1 like monero since june 2018 + const uint8_t tmp = ((const uint8_t*)(state))[11]; + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; + ((uint8_t*)(state))[11] = tmp ^ ((0x75310 >> index) & 0x30); + } +} + struct cryptonight_ctx { - uint8_t long_state[MEMORY] __attribute((aligned(16))); + uint8_t _ALIGN(16) long_state[MEMORY]; union cn_slow_hash_state state; - uint8_t text[INIT_SIZE_BYTE] __attribute((aligned(16))); - uint8_t a[AES_BLOCK_SIZE] __attribute__((aligned(16))); - uint8_t b[AES_BLOCK_SIZE] __attribute__((aligned(16))); - uint8_t c[AES_BLOCK_SIZE] __attribute__((aligned(16))); + uint8_t _ALIGN(16) text[INIT_SIZE_BYTE]; + uint8_t _ALIGN(16) a[AES_BLOCK_SIZE]; + uint8_t _ALIGN(16) b[AES_BLOCK_SIZE]; + uint8_t _ALIGN(16) c[AES_BLOCK_SIZE]; oaes_ctx* aes_ctx; }; -void cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cryptonight_ctx* ctx) { +static void cryptolight_hash_ctx(void* output, const void* input, int len, struct cryptonight_ctx* ctx, int variant) +{ + size_t i, j; + hash_process(&ctx->state.hs, (const uint8_t*) input, len); ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); - size_t i, j; memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + const uint64_t tweak = variant ? *((uint64_t*) (((uint8_t*)input) + 35)) ^ ctx->state.hs.w[24] : 0; + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 0], ctx->aes_ctx->key->exp_data); @@ -144,13 +211,16 @@ void cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cr aesb_single_round(&ctx->long_state[j], ctx->c, ctx->a); xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); /* Iteration 2 */ - mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)]); + cryptolight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)], variant, tweak); + /* Iteration 3 */ j = e2i(ctx->a); aesb_single_round(&ctx->long_state[j], ctx->b, ctx->a); xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); /* Iteration 4 */ - mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)]); + cryptolight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)], variant, tweak); } memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); @@ -180,18 +250,23 @@ void cryptonight_hash_ctx(void* output, const void* input, size_t len, struct cr oaes_free((OAES_CTX **) &ctx->aes_ctx); } -void cryptonight_hash(void* output, const void* input, size_t len) { +void cryptolight_hash(void* output, const void* input) { + const int variant = 1; struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); - cryptonight_hash_ctx(output, input, len, ctx); + cryptolight_hash_ctx(output, input, 76, ctx, variant); free(ctx); } -void cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, struct cryptonight_ctx* ctx) { - hash_process(&ctx->state.hs, (const uint8_t*) input, len); - ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); +static void cryptolight_hash_ctx_aes_ni(void* output, const void* input, int len, struct cryptonight_ctx* ctx, int variant) +{ size_t i, j; + + hash_process(&ctx->state.hs, (const uint8_t*)input, len); + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + const uint64_t tweak = variant ? *((uint64_t*) (((uint8_t*)input) + 35)) ^ ctx->state.hs.w[24] : 0; + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 0], ctx->aes_ctx->key->exp_data); @@ -218,13 +293,16 @@ void cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, st fast_aesb_single_round(&ctx->long_state[j], ctx->c, ctx->a); xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); /* Iteration 2 */ - mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)]); + cryptolight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)], variant, tweak); + /* Iteration 3 */ j = e2i(ctx->a); fast_aesb_single_round(&ctx->long_state[j], ctx->b, ctx->a); xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); /* Iteration 4 */ - mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)]); + cryptolight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)], variant, tweak); } memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); @@ -254,34 +332,39 @@ void cryptonight_hash_ctx_aes_ni(void* output, const void* input, size_t len, st oaes_free((OAES_CTX **) &ctx->aes_ctx); } -int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) { +int scanhash_cryptolight(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + const int variant = 1; // since june 2018 + uint32_t _ALIGN(128) hash[HASH_SIZE / 4]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + uint32_t *nonceptr = (uint32_t*) (((char*)pdata) + 39); uint32_t n = *nonceptr - 1; const uint32_t first_nonce = n + 1; - const uint32_t Htarg = ptarget[7]; - uint32_t hash[HASH_SIZE / 4] __attribute__((aligned(32))); struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); if (aes_ni_supported) { do { *nonceptr = ++n; - cryptonight_hash_ctx_aes_ni(hash, pdata, 76, ctx); + cryptolight_hash_ctx_aes_ni(hash, pdata, 76, ctx, variant); if (unlikely(hash[7] < ptarget[7])) { + work_set_target_ratio(work, hash); *hashes_done = n - first_nonce + 1; free(ctx); - return true; + return 1; } } while (likely((n <= max_nonce && !work_restart[thr_id].restart))); } else { do { *nonceptr = ++n; - cryptonight_hash_ctx(hash, pdata, 76, ctx); + cryptolight_hash_ctx(hash, pdata, 76, ctx, variant); if (unlikely(hash[7] < ptarget[7])) { + work_set_target_ratio(work, hash); *hashes_done = n - first_nonce + 1; free(ctx); - return true; + return 1; } } while (likely((n <= max_nonce && !work_restart[thr_id].restart))); } @@ -290,3 +373,4 @@ int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, *hashes_done = n - first_nonce + 1; return 0; } + diff --git a/algo/cryptonight.c b/algo/cryptonight.c new file mode 100644 index 000000000..f9be9bda3 --- /dev/null +++ b/algo/cryptonight.c @@ -0,0 +1,384 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Modified for CPUminer by Lucas Jones + +#include "miner.h" + +#if defined(__arm__) || defined(_MSC_VER) +#ifndef NOASM +#define NOASM +#endif +#endif + +#include "crypto/oaes_lib.h" +#include "crypto/c_keccak.h" +#include "crypto/c_groestl.h" +#include "crypto/c_blake256.h" +#include "crypto/c_jh.h" +#include "crypto/c_skein.h" +#include "crypto/int-util.h" +#include "crypto/hash-ops.h" + +#if USE_INT128 + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ < 6 +typedef unsigned int uint128_t __attribute__ ((__mode__ (TI))); +#elif defined (_MSC_VER) +/* only for mingw64 on windows */ +#undef USE_INT128 +#define USE_INT128 (0) +#else +typedef __uint128_t uint128_t; +#endif + +#endif + +#define LITE 0 +#if LITE /* cryptonight-light */ +#define MEMORY (1 << 20) +#define ITER (1 << 19) +#else +#define MEMORY (1 << 21) /* 2 MiB */ +#define ITER (1 << 20) +#endif + +#define AES_BLOCK_SIZE 16 +#define AES_KEY_SIZE 32 /*16*/ +#define INIT_SIZE_BLK 8 +#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE) + +#pragma pack(push, 1) +union cn_slow_hash_state { + union hash_state hs; + struct { + uint8_t k[64]; + uint8_t init[INIT_SIZE_BYTE]; + }; +}; +#pragma pack(pop) + +static void do_blake_hash(const void* input, size_t len, char* output) { + blake256_hash((uint8_t*)output, input, len); +} + +static void do_groestl_hash(const void* input, size_t len, char* output) { + groestl(input, len * 8, (uint8_t*)output); +} + +static void do_jh_hash(const void* input, size_t len, char* output) { + int r = jh_hash(HASH_SIZE * 8, input, 8 * len, (uint8_t*)output); + assert(likely(SUCCESS == r)); +} + +static void do_skein_hash(const void* input, size_t len, char* output) { + int r = skein_hash(8 * HASH_SIZE, input, 8 * len, (uint8_t*)output); + assert(likely(SKEIN_SUCCESS == r)); +} + +extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); +extern int aesb_pseudo_round_mut(uint8_t *val, uint8_t *expandedKey); +#if !defined(_MSC_VER) && !defined(NOASM) +extern int fast_aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); +extern int fast_aesb_pseudo_round_mut(uint8_t *val, uint8_t *expandedKey); +#else +#define fast_aesb_single_round aesb_single_round +#define fast_aesb_pseudo_round_mut aesb_pseudo_round_mut +#endif + +#if defined(NOASM) || !defined(__x86_64__) +static uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} +#else +extern uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi); +#endif + +static void (* const extra_hashes[4])(const void *, size_t, char *) = { + do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash +}; + + +static inline size_t e2i(const uint8_t* a) { +#if !LITE + return ((uint32_t *)a)[0] & 0x1FFFF0; +#else + return ((uint32_t *)a)[0] & 0xFFFF0; +#endif +} + +static inline void mul_sum_xor_dst(const uint8_t* a, uint8_t* c, uint8_t* dst, int variant, const uint64_t tweak) { + uint64_t hi, lo = mul128(((uint64_t*) a)[0], ((uint64_t*) dst)[0], &hi) + ((uint64_t*) c)[1]; + hi += ((uint64_t*) c)[0]; + ((uint64_t*) c)[0] = ((uint64_t*) dst)[0] ^ hi; + ((uint64_t*) c)[1] = ((uint64_t*) dst)[1] ^ lo; + ((uint64_t*) dst)[0] = hi; + ((uint64_t*) dst)[1] = variant ? lo ^ tweak : lo; +} + +static inline void xor_blocks(uint8_t* a, const uint8_t* b) { +#if USE_INT128 + *((uint128_t*) a) ^= *((uint128_t*) b); +#else + ((uint64_t*) a)[0] ^= ((uint64_t*) b)[0]; + ((uint64_t*) a)[1] ^= ((uint64_t*) b)[1]; +#endif +} + +static inline void xor_blocks_dst(const uint8_t* a, const uint8_t* b, uint8_t* dst) { +#if USE_INT128 + *((uint128_t*) dst) = *((uint128_t*) a) ^ *((uint128_t*) b); +#else + ((uint64_t*) dst)[0] = ((uint64_t*) a)[0] ^ ((uint64_t*) b)[0]; + ((uint64_t*) dst)[1] = ((uint64_t*) a)[1] ^ ((uint64_t*) b)[1]; +#endif +} + +static void cryptonight_store_variant(void* state, int variant) { + if (variant == 1) { + const uint8_t tmp = ((const uint8_t*)(state))[11]; + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; + ((uint8_t*)(state))[11] = tmp ^ ((0x75310 >> index) & 0x30); + } +} + +struct cryptonight_ctx { + uint8_t _ALIGN(16) long_state[MEMORY]; + union cn_slow_hash_state state; + uint8_t _ALIGN(16) text[INIT_SIZE_BYTE]; + uint8_t _ALIGN(16) a[AES_BLOCK_SIZE]; + uint8_t _ALIGN(16) b[AES_BLOCK_SIZE]; + uint8_t _ALIGN(16) c[AES_BLOCK_SIZE]; + oaes_ctx* aes_ctx; +}; + +static void cryptonight_hash_ctx(void* output, const void* input, int len, struct cryptonight_ctx* ctx, int variant) +{ + size_t i, j; + + hash_process(&ctx->state.hs, (const uint8_t*) input, len); + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + const uint64_t tweak = variant ? *((uint64_t*) (((uint8_t*)input) + 35)) ^ ctx->state.hs.w[24] : 0; + + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); + for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 0], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 1], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 2], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 3], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 4], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 5], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 6], ctx->aes_ctx->key->exp_data); + aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 7], ctx->aes_ctx->key->exp_data); + memcpy(&ctx->long_state[i], ctx->text, INIT_SIZE_BYTE); + } + + xor_blocks_dst(&ctx->state.k[0], &ctx->state.k[32], ctx->a); + xor_blocks_dst(&ctx->state.k[16], &ctx->state.k[48], ctx->b); + + for (i = 0; likely(i < ITER / 4); ++i) { + /* Dependency chain: address -> read value ------+ + * written value <-+ hard function (AES or MUL) <+ + * next address <-+ + */ + /* Iteration 1 */ + j = e2i(ctx->a); + aesb_single_round(&ctx->long_state[j], ctx->c, ctx->a); + xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); + /* Iteration 2 */ + cryptonight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)], variant, tweak); + + /* Iteration 3 */ + j = e2i(ctx->a); + aesb_single_round(&ctx->long_state[j], ctx->b, ctx->a); + xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); + /* Iteration 4 */ + cryptonight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)], variant, tweak); + } + + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE); + for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { + xor_blocks(&ctx->text[0 * AES_BLOCK_SIZE], &ctx->long_state[i + 0 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[0 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[1 * AES_BLOCK_SIZE], &ctx->long_state[i + 1 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[1 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[2 * AES_BLOCK_SIZE], &ctx->long_state[i + 2 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[2 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[3 * AES_BLOCK_SIZE], &ctx->long_state[i + 3 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[3 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[4 * AES_BLOCK_SIZE], &ctx->long_state[i + 4 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[4 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[5 * AES_BLOCK_SIZE], &ctx->long_state[i + 5 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[5 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[6 * AES_BLOCK_SIZE], &ctx->long_state[i + 6 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[6 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[7 * AES_BLOCK_SIZE], &ctx->long_state[i + 7 * AES_BLOCK_SIZE]); + aesb_pseudo_round_mut(&ctx->text[7 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + } + memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); + hash_permutation(&ctx->state.hs); + /*memcpy(hash, &state, 32);*/ + extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); + oaes_free((OAES_CTX **) &ctx->aes_ctx); +} + +void cryptonight_hash(void* output, const void* input) { + const int variant = 1; + struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); + cryptonight_hash_ctx(output, input, 76, ctx, variant); + free(ctx); +} + +void cryptonight_hash_v1(void* output, const void* input) { + const int variant = 0; + struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); + cryptonight_hash_ctx(output, input, 76, ctx, variant); + free(ctx); +} + +static void cryptonight_hash_ctx_aes_ni(void* output, const void* input, int len, struct cryptonight_ctx* ctx, int variant) +{ + size_t i, j; + + hash_process(&ctx->state.hs, (const uint8_t*)input, len); + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + const uint64_t tweak = variant ? *((uint64_t*) (((uint8_t*)input) + 35)) ^ ctx->state.hs.w[24] : 0; + + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); + for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 0], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 1], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 2], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 3], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 4], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 5], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 6], ctx->aes_ctx->key->exp_data); + fast_aesb_pseudo_round_mut(&ctx->text[AES_BLOCK_SIZE * 7], ctx->aes_ctx->key->exp_data); + memcpy(&ctx->long_state[i], ctx->text, INIT_SIZE_BYTE); + } + + xor_blocks_dst(&ctx->state.k[0], &ctx->state.k[32], ctx->a); + xor_blocks_dst(&ctx->state.k[16], &ctx->state.k[48], ctx->b); + + for (i = 0; likely(i < ITER / 4); ++i) { + /* Dependency chain: address -> read value ------+ + * written value <-+ hard function (AES or MUL) <+ + * next address <-+ + */ + /* Iteration 1 */ + j = e2i(ctx->a); + fast_aesb_single_round(&ctx->long_state[j], ctx->c, ctx->a); + xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); + /* Iteration 2 */ + cryptonight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[e2i(ctx->c)], variant, tweak); + + /* Iteration 3 */ + j = e2i(ctx->a); + fast_aesb_single_round(&ctx->long_state[j], ctx->b, ctx->a); + xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); + /* Iteration 4 */ + cryptonight_store_variant(&ctx->long_state[j], variant); + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[e2i(ctx->b)], variant, tweak); + } + + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE); + for (i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) { + xor_blocks(&ctx->text[0 * AES_BLOCK_SIZE], &ctx->long_state[i + 0 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[0 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[1 * AES_BLOCK_SIZE], &ctx->long_state[i + 1 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[1 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[2 * AES_BLOCK_SIZE], &ctx->long_state[i + 2 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[2 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[3 * AES_BLOCK_SIZE], &ctx->long_state[i + 3 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[3 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[4 * AES_BLOCK_SIZE], &ctx->long_state[i + 4 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[4 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[5 * AES_BLOCK_SIZE], &ctx->long_state[i + 5 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[5 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[6 * AES_BLOCK_SIZE], &ctx->long_state[i + 6 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[6 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + xor_blocks(&ctx->text[7 * AES_BLOCK_SIZE], &ctx->long_state[i + 7 * AES_BLOCK_SIZE]); + fast_aesb_pseudo_round_mut(&ctx->text[7 * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); + } + memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); + hash_permutation(&ctx->state.hs); + /*memcpy(hash, &state, 32);*/ + extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); + oaes_free((OAES_CTX **) &ctx->aes_ctx); +} + +int scanhash_cryptonight(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[HASH_SIZE / 4]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + uint32_t *nonceptr = (uint32_t*) (((char*)pdata) + 39); + uint32_t n = *nonceptr - 1; + const uint32_t first_nonce = n + 1; + + // todo: make it dynamic + const int variant = 1; + + struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); + + if (aes_ni_supported) { + do { + *nonceptr = ++n; + cryptonight_hash_ctx_aes_ni(hash, pdata, 76, ctx, variant); + if (unlikely(hash[7] < ptarget[7])) { + work_set_target_ratio(work, hash); + *hashes_done = n - first_nonce + 1; + free(ctx); + return 1; + } + } while (likely((n <= max_nonce && !work_restart[thr_id].restart))); + } else { + do { + *nonceptr = ++n; + cryptonight_hash_ctx(hash, pdata, 76, ctx, variant); + if (unlikely(hash[7] < ptarget[7])) { + work_set_target_ratio(work, hash); + *hashes_done = n - first_nonce + 1; + free(ctx); + return 1; + } + } while (likely((n <= max_nonce && !work_restart[thr_id].restart))); + } + + free(ctx); + *hashes_done = n - first_nonce + 1; + return 0; +} diff --git a/algo/decred.c b/algo/decred.c new file mode 100644 index 000000000..5c6939b5e --- /dev/null +++ b/algo/decred.c @@ -0,0 +1,90 @@ +#include "miner.h" + +#include "sha3/sph_blake.h" + +#include +#include +#include + +static __thread sph_blake256_context blake_mid; +static __thread bool ctx_midstate_done = false; + +void decred_hash(void *state, const void *input) +{ + #define MIDSTATE_LEN 128 + sph_blake256_context ctx; + + uint8_t *ending = (uint8_t*) input; + ending += MIDSTATE_LEN; + + if (!ctx_midstate_done) { + sph_blake256_init(&blake_mid); + sph_blake256(&blake_mid, input, MIDSTATE_LEN); + ctx_midstate_done = true; + } + memcpy(&ctx, &blake_mid, sizeof(blake_mid)); + + sph_blake256(&ctx, ending, (180 - MIDSTATE_LEN)); + sph_blake256_close(&ctx, state); +} + +void decred_hash_simple(void *state, const void *input) +{ + sph_blake256_context ctx; + sph_blake256_init(&ctx); + sph_blake256(&ctx, input, 180); + sph_blake256_close(&ctx, state); +} + +int scanhash_decred(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) endiandata[48]; + uint32_t _ALIGN(128) hash32[8]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + #define DCR_NONCE_OFT32 35 + + const uint32_t first_nonce = pdata[DCR_NONCE_OFT32]; + const uint32_t HTarget = opt_benchmark ? 0x7f : ptarget[7]; + + uint32_t n = first_nonce; + + ctx_midstate_done = false; + +#if 1 + memcpy(endiandata, pdata, 180); +#else + for (int k=0; k < (180/4); k++) + be32enc(&endiandata[k], pdata[k]); +#endif + +#ifdef DEBUG_ALGO + if (!thr_id) applog(LOG_DEBUG,"[%d] Target=%08x %08x", thr_id, ptarget[6], ptarget[7]); +#endif + + do { + //be32enc(&endiandata[DCR_NONCE_OFT32], n); + endiandata[DCR_NONCE_OFT32] = n; + decred_hash(hash32, endiandata); + + if (hash32[7] <= HTarget && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; +#ifdef DEBUG_ALGO + applog(LOG_BLUE, "Nonce : %08x %08x", n, swab32(n)); + applog_hash(ptarget); + applog_compare_hash(hash32, ptarget); +#endif + pdata[DCR_NONCE_OFT32] = n; + return 1; + } + + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[DCR_NONCE_OFT32] = n; + return 0; +} diff --git a/algo/drop.c b/algo/drop.c new file mode 100644 index 000000000..1e8f2cb1b --- /dev/null +++ b/algo/drop.c @@ -0,0 +1,209 @@ +/** + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2015 kernels10, tpruvot + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file drop.c + * @author kernels10 + * @author tpruvot + */ + +#define POK_BOOL_MASK 0x00008000 +#define POK_DATA_MASK 0xFFFF0000 + +#include "miner.h" + +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_echo.h" +#include "sha3/sph_fugue.h" +#include "sha3/sph_luffa.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_shavite.h" + +static void shiftr_lp(const uint32_t *input, uint32_t *output, unsigned int shift) +{ + if(!shift) { + memcpy(output, input, 64); + return; + } + + memset(output, 0, 64); + for(int i = 0; i < 15; ++i) { + output[i + 1] |= (input[i] >> (32 - shift)); + output[i] |= (input[i] << shift); + } + + output[15] |= (input[15] << shift); + return; +} + +static void switchHash(const void *input, void *output, int id) +{ + sph_keccak512_context ctx_keccak; + sph_blake512_context ctx_blake; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_luffa512_context ctx_luffa; + sph_echo512_context ctx_echo; + sph_simd512_context ctx_simd; + sph_cubehash512_context ctx_cubehash; + sph_fugue512_context ctx_fugue; + sph_shavite512_context ctx_shavite; + + switch(id) { + case 0: + sph_keccak512_init(&ctx_keccak); sph_keccak512(&ctx_keccak, input, 64); sph_keccak512_close(&ctx_keccak, output); + break; + case 1: + sph_blake512_init(&ctx_blake); sph_blake512(&ctx_blake, input, 64); sph_blake512_close(&ctx_blake, output); + break; + case 2: + sph_groestl512_init(&ctx_groestl); sph_groestl512(&ctx_groestl, input, 64); sph_groestl512_close(&ctx_groestl, output); + break; + case 3: + sph_skein512_init(&ctx_skein); sph_skein512(&ctx_skein, input, 64); sph_skein512_close(&ctx_skein, output); + break; + case 4: + sph_luffa512_init(&ctx_luffa); sph_luffa512(&ctx_luffa, input, 64); sph_luffa512_close(&ctx_luffa, output); + break; + case 5: + sph_echo512_init(&ctx_echo); sph_echo512(&ctx_echo, input, 64); sph_echo512_close(&ctx_echo, output); + break; + case 6: + sph_shavite512_init(&ctx_shavite); sph_shavite512(&ctx_shavite, input, 64); sph_shavite512_close(&ctx_shavite, output); + break; + case 7: + sph_fugue512_init(&ctx_fugue); sph_fugue512(&ctx_fugue, input, 64); sph_fugue512_close(&ctx_fugue, output); + break; + case 8: + sph_simd512_init(&ctx_simd); sph_simd512(&ctx_simd, input, 64); sph_simd512_close(&ctx_simd, output); + break; + case 9: + sph_cubehash512_init(&ctx_cubehash); sph_cubehash512(&ctx_cubehash, input, 64); sph_cubehash512_close(&ctx_cubehash, output); + break; + default: + break; + } +} + +void droplp_hash(void *state, const void *input) +{ + uint32_t _ALIGN(64) hash[2][16]; + sph_jh512_context ctx_jh; + uint32_t *hashA = hash[0]; + uint32_t *hashB = hash[1]; + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, input, 80); + sph_jh512_close(&ctx_jh, (void*)(hashA)); + + unsigned int startPosition = hashA[0] % 31; + unsigned int i = 0; + int j = 0; + int start = 0; + + for (i = startPosition; i < 31; i+=9) { + start = i % 10; + for (j = start; j < 10; j++) { + shiftr_lp(hashA, hashB, (i & 3)); + switchHash((const void*)hashB, (void*)hashA, j); + } + for (j = 0; j < start; j++) { + shiftr_lp(hashA, hashB, (i & 3)); + switchHash((const void*)hashB, (void*)hashA, j); + } + } + for (i = 0; i < startPosition; i += 9) { + start = i % 10; + for (j = start; j < 10; j++) { + shiftr_lp(hashA, hashB, (i & 3)); + switchHash((const void*)hashB, (void*)hashA, j); + } + for (j = 0; j < start; j++) { + shiftr_lp(hashA, hashB, (i & 3)); + switchHash((const void*)hashB, (void*)hashA, j); + } + } + + memcpy(state, hashA, 32); +} + +static void droplp_hash_pok(void *output, uint32_t *pdata, const uint32_t version) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t pok; + + pdata[0] = version; + droplp_hash(hash, pdata); + + // fill PoK + pok = version | (hash[0] & POK_DATA_MASK); + if (pdata[0] != pok) { + pdata[0] = pok; + droplp_hash(hash, pdata); + } + memcpy(output, hash, 32); +} + +int scanhash_drop(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[16]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t version = pdata[0] & (~POK_DATA_MASK); + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + #define tmpdata pdata + + if (opt_benchmark) + ptarget[7] = 0x07ff; + + const uint32_t htarg = ptarget[7]; + + do { + tmpdata[19] = nonce; + droplp_hash_pok(hash, tmpdata, version); + + if (hash[7] <= htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[0] = tmpdata[0]; + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/fresh.c b/algo/fresh.c similarity index 51% rename from fresh.c rename to algo/fresh.c index 8193cabc1..619bfaa18 100644 --- a/fresh.c +++ b/algo/fresh.c @@ -11,51 +11,50 @@ //#define DEBUG_ALGO -inline void freshhash(void* output, const void* input, uint32_t len) +extern void freshhash(void* output, const void* input, uint32_t len) { unsigned char hash[128]; // uint32_t hashA[16], hashB[16]; #define hashA hash #define hashB hash+64 - memset(hash, 0, 128); - sph_shavite512_context ctx_shavite1; - sph_simd512_context ctx_simd1; - sph_echo512_context ctx_echo1; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; - sph_shavite512_init(&ctx_shavite1); - sph_shavite512(&ctx_shavite1, input, len); - sph_shavite512_close(&ctx_shavite1, hashA); + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, input, len); + sph_shavite512_close(&ctx_shavite, hashA); - sph_simd512_init(&ctx_simd1); - sph_simd512(&ctx_simd1, hashA, 64); - sph_simd512_close(&ctx_simd1, hashB); + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hashA, 64); + sph_simd512_close(&ctx_simd, hashB); - sph_shavite512_init(&ctx_shavite1); - sph_shavite512(&ctx_shavite1, hashB, 64); - sph_shavite512_close(&ctx_shavite1, hashA); + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hashB, 64); + sph_shavite512_close(&ctx_shavite, hashA); - sph_simd512_init(&ctx_simd1); - sph_simd512(&ctx_simd1, hashA, 64); - sph_simd512_close(&ctx_simd1, hashB); + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hashA, 64); + sph_simd512_close(&ctx_simd, hashB); - sph_echo512_init(&ctx_echo1); - sph_echo512(&ctx_echo1, hashB, 64); - sph_echo512_close(&ctx_echo1, hashA); + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hashB, 64); + sph_echo512_close(&ctx_echo, hashA); memcpy(output, hash, 32); } -int scanhash_fresh(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) +int scanhash_fresh(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) { - uint32_t len = 80; + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; - uint32_t n = pdata[19] - 1; const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; - - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; + const uint32_t len = 80; + uint32_t n = pdata[19] - 1; uint64_t htmax[] = { 0, @@ -82,25 +81,27 @@ int scanhash_fresh(int thr_id, uint32_t *pdata, const uint32_t *ptarget, if (Htarg != 0) printf("[%d] Htarg=%X\n", thr_id, Htarg); #endif - for (int m=0; m < sizeof(masks); m++) { + for (int m=0; m < 6; m++) { if (Htarg <= htmax[m]) { uint32_t mask = masks[m]; do { pdata[19] = ++n; be32enc(&endiandata[19], n); - freshhash(hash64, &endiandata, len); + freshhash(hash32, endiandata, len); #ifndef DEBUG_ALGO - if ((!(hash64[7] & mask)) && fulltest(hash64, ptarget)) { + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; - return true; + return 1; } #else if (!(n % 0x1000) && !thr_id) printf("."); - if (!(hash64[7] & mask)) { + if (!(hash32[7] & mask)) { printf("[%d]",thr_id); - if (fulltest(hash64, ptarget)) { + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; - return true; + return 1; } } #endif diff --git a/algo/geek.c b/algo/geek.c new file mode 100644 index 000000000..c52b83fd1 --- /dev/null +++ b/algo/geek.c @@ -0,0 +1,106 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void geekhash(void *output, const void *input) +{ + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_echo512_context ctx_echo; + sph_shabal512_context ctx_shabal; + sph_groestl512_context ctx_groestl; + sph_cubehash512_context ctx_cubehash; + sph_keccak512_context ctx_keccak; + sph_hamsi512_context ctx_hamsi; + sph_simd512_context ctx_simd; + + uint32_t _ALIGN(128) hash[16]; + + sph_blake512_init(&ctx_blake); + sph_blake512 (&ctx_blake, input, 80); + sph_blake512_close (&ctx_blake, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_echo512_init (&ctx_echo); + sph_echo512 (&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_shabal512_init (&ctx_shabal); + sph_shabal512 (&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_cubehash512_init (&ctx_cubehash); + sph_cubehash512 (&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_hamsi512_init (&ctx_hamsi); + sph_hamsi512 (&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_simd512_init (&ctx_simd); + sph_simd512 (&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + memcpy(output, hash, 32); +} + +int scanhash_geek(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + geekhash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/groestl.c b/algo/groestl.c new file mode 100644 index 000000000..1f58a74bf --- /dev/null +++ b/algo/groestl.c @@ -0,0 +1,64 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_groestl.h" + +// static __thread sph_groestl512_context ctx; + +void groestlhash(void *output, const void *input) +{ + uint32_t _ALIGN(32) hash[16]; + sph_groestl512_context ctx; + + // memset(&hash[0], 0, sizeof(hash)); + + sph_groestl512_init(&ctx); + sph_groestl512(&ctx, input, 80); + sph_groestl512_close(&ctx, hash); + + //sph_groestl512_init(&ctx); + sph_groestl512(&ctx, hash, 64); + sph_groestl512_close(&ctx, hash); + + memcpy(output, hash, 32); +} + +int scanhash_groestl(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x00ff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + groestlhash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/heavy.c b/algo/heavy.c new file mode 100644 index 000000000..103303fa8 --- /dev/null +++ b/algo/heavy.c @@ -0,0 +1,106 @@ +#include +#include +#include + +#include "miner.h" +#include "sha3/sph_hefty1.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_blake.h" +#include "sha3/sph_groestl.h" + +/* Combines top 64-bits from each hash into a single hash */ +static void combine_hashes(uint32_t *out, uint32_t *hash1, uint32_t *hash2, uint32_t *hash3, uint32_t *hash4) +{ + uint32_t *hash[4] = { hash1, hash2, hash3, hash4 }; + + /* Transpose first 64 bits of each hash into out */ + memset(out, 0, 32); + int bits = 0; + for (unsigned int i = 7; i >= 6; i--) { + for (uint32_t mask = 0x80000000; mask; mask >>= 1) { + for (unsigned int k = 0; k < 4; k++) { + out[(255 - bits)/32] <<= 1; + if ((hash[k][i] & mask) != 0) + out[(255 - bits)/32] |= 1; + bits++; + } + } + } +} + +extern void heavyhash(unsigned char* output, const unsigned char* input, int len) +{ + unsigned char _ALIGN(128) hash1[32]; + HEFTY1(input, len, hash1); + + /* HEFTY1 is new, so take an extra security measure to eliminate + * the possiblity of collisions: + * + * Hash(x) = SHA256(x + HEFTY1(x)) + * + * N.B. '+' is concatenation. + */ + unsigned char hash2[32];; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, input, len); + SHA256_Update(&ctx, hash1, sizeof(hash1)); + SHA256_Final(hash2, &ctx); + + /* Additional security: Do not rely on a single cryptographic hash + * function. Instead, combine the outputs of 4 of the most secure + * cryptographic hash functions-- SHA256, KECCAK512, GROESTL512 + * and BLAKE512. + */ + + uint32_t hash3[16]; + sph_keccak512_context keccakCtx; + sph_keccak512_init(&keccakCtx); + sph_keccak512(&keccakCtx, input, len); + sph_keccak512(&keccakCtx, hash1, sizeof(hash1)); + sph_keccak512_close(&keccakCtx, (void *)&hash3); + + uint32_t hash4[16]; + sph_groestl512_context groestlCtx; + sph_groestl512_init(&groestlCtx); + sph_groestl512(&groestlCtx, input, len); + sph_groestl512(&groestlCtx, hash1, sizeof(hash1)); + sph_groestl512_close(&groestlCtx, (void *)&hash4); + + uint32_t hash5[16]; + sph_blake512_context blakeCtx; + sph_blake512_init(&blakeCtx); + sph_blake512(&blakeCtx, input, len); + sph_blake512(&blakeCtx, (unsigned char *)&hash1, sizeof(hash1)); + sph_blake512_close(&blakeCtx, (void *)&hash5); + + uint32_t *final = (uint32_t *)output; + combine_hashes(final, (uint32_t *)hash2, hash3, hash4, hash5); +} + +int scanhash_heavy(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + const uint32_t Htarg = ptarget[7]; + do { + pdata[19] = nonce; + heavyhash((unsigned char *)hash, (unsigned char *)pdata, 80); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = pdata[19] - first_nonce; + return 0; +} \ No newline at end of file diff --git a/algo/ink.c b/algo/ink.c new file mode 100644 index 000000000..59ba48adf --- /dev/null +++ b/algo/ink.c @@ -0,0 +1,55 @@ +#include "miner.h" + +#include +#include + +#include "sha3/sph_shavite.h" + +extern void inkhash(void *state, const void *input) +{ + uint32_t _ALIGN(128) hash[16]; + sph_shavite512_context ctx_shavite; + + sph_shavite512_init(&ctx_shavite); + sph_shavite512 (&ctx_shavite, (const void*) input, 80); + sph_shavite512_close(&ctx_shavite, (void*) hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, (const void*) hash, 64); + sph_shavite512_close(&ctx_shavite, (void*) hash); + + memcpy(state, hash, 32); +} + +int scanhash_ink(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + uint32_t n = pdata[19] - 1; + const uint32_t first_nonce = pdata[19]; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + const uint32_t Htarg = ptarget[7]; + do { + be32enc(&endiandata[19], n); + inkhash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = n; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/jha.c b/algo/jha.c new file mode 100644 index 000000000..2b45d19d6 --- /dev/null +++ b/algo/jha.c @@ -0,0 +1,124 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_keccak.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_blake.h" +#include "sha3/sph_jh.h" + +void jha_hash(void *output, const void *input) +{ + uint8_t _ALIGN(128) hash[64]; + + sph_blake512_context ctx_blake; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + + // JHA v8 input is 80 bytes + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, input, 80); + sph_keccak512_close(&ctx_keccak, (&hash)); + + // Heavy & Light Pair Loop + for (int round = 0; round < 3; round++) + { + if (hash[0] & 0x01) { + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, (&hash), 64); + sph_groestl512_close(&ctx_groestl, (&hash)); + } else { + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, (&hash), 64); + sph_skein512_close(&ctx_skein, (&hash)); + } + + if (hash[0] & 0x01) { + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, (&hash), 64); + sph_blake512_close(&ctx_blake, (&hash)); + } else { + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, (&hash), 64); + sph_jh512_close(&ctx_jh, (&hash)); + } + } + + memcpy(output, hash, 32); +} + +int scanhash_jha(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + uint32_t n = pdata[19] - 1; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + jha_hash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/keccak.c b/algo/keccak.c new file mode 100644 index 000000000..65e7bae28 --- /dev/null +++ b/algo/keccak.c @@ -0,0 +1,51 @@ +#include "miner.h" + +#include +#include + +#include "sha3/sph_keccak.h" + +extern void keccakhash(void *state, const void *input) +{ + sph_keccak256_context ctx_keccak; + uint32_t hash[32]; + + sph_keccak256_init(&ctx_keccak); + sph_keccak256 (&ctx_keccak,input, 80); + sph_keccak256_close(&ctx_keccak, hash); + + memcpy(state, hash, 32); +} + +int scanhash_keccak(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + uint32_t n = pdata[19] - 1; + const uint32_t first_nonce = pdata[19]; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + const uint32_t Htarg = ptarget[7]; + do { + + pdata[19] = ++n; + be32enc(&endiandata[19], n); + keccakhash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = n; + *hashes_done = pdata[19] - first_nonce; + return true; + } + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/lbry.c b/algo/lbry.c new file mode 100644 index 000000000..6da799194 --- /dev/null +++ b/algo/lbry.c @@ -0,0 +1,102 @@ +/** + * Lbry sph Implementation + * tpruvot@github July 2016 + */ + +#include "miner.h" + +#include +#include + +#include "sha3/sph_sha2.h" +#include "sha3/sph_ripemd.h" + +#define A 64 + +typedef struct { + sph_sha256_context sha256; + sph_sha512_context sha512; + sph_ripemd160_context ripemd; +} lbryhash_context_holder; + +static __thread lbryhash_context_holder ctx; +static __thread bool ctx_init = false; + +static void lbry_initstate() +{ + sph_sha256_init(&ctx.sha256); + sph_sha512_init(&ctx.sha512); + sph_ripemd160_init(&ctx.ripemd); + ctx_init = true; +} + +void lbry_hash(void* output, const void* input) +{ + uint32_t _ALIGN(A) hashA[16]; + uint32_t _ALIGN(A) hashB[8]; + uint32_t _ALIGN(A) hashC[8]; + + //memset(&hashA[8], 0, 32); + + // sha256d + sph_sha256(&ctx.sha256, input, 112); + sph_sha256_close(&ctx.sha256, hashA); + sph_sha256(&ctx.sha256, hashA, 32); + sph_sha256_close(&ctx.sha256, hashA); + + sph_sha512(&ctx.sha512, hashA, 32); + sph_sha512_close(&ctx.sha512, hashA); + + sph_ripemd160(&ctx.ripemd, hashA, 32); + sph_ripemd160_close(&ctx.ripemd, hashB); + + sph_ripemd160(&ctx.ripemd, &hashA[8], 32); // weird + sph_ripemd160_close(&ctx.ripemd, hashC); + + sph_sha256(&ctx.sha256, hashB, 20); + sph_sha256(&ctx.sha256, hashC, 20); + sph_sha256_close(&ctx.sha256, hashA); + + sph_sha256(&ctx.sha256, hashA, 32); + sph_sha256_close(&ctx.sha256, hashA); + + memcpy(output, hashA, 32); +} + +int scanhash_lbry(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(A) vhashcpu[8]; + uint32_t _ALIGN(A) endiandata[28]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[27]; + + uint32_t n = first_nonce; + + for (int i=0; i < 27; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + if (!ctx_init) lbry_initstate(); + + do { + be32enc(&endiandata[27], n); + lbry_hash(vhashcpu, endiandata); + + if (vhashcpu[7] <= Htarg && fulltest(vhashcpu, ptarget)) { + work_set_target_ratio(work, vhashcpu); + *hashes_done = n - first_nonce + 1; + work->resnonce = pdata[27] = n; // to check + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[27] = n; + + return 0; +} diff --git a/algo/luffa.c b/algo/luffa.c new file mode 100644 index 000000000..5ce046ceb --- /dev/null +++ b/algo/luffa.c @@ -0,0 +1,55 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_luffa.h" + +void luffahash(void *output, const void *input) +{ + unsigned char _ALIGN(128) hash[64]; + sph_luffa512_context ctx_luffa; + + sph_luffa512_init(&ctx_luffa); + sph_luffa512 (&ctx_luffa, input, 80); + sph_luffa512_close(&ctx_luffa, (void*) hash); + + memcpy(output, hash, 32); +} + +int scanhash_luffa(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + luffahash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/lyra2re.c b/algo/lyra2re.c new file mode 100644 index 000000000..a0f2996d3 --- /dev/null +++ b/algo/lyra2re.c @@ -0,0 +1,77 @@ +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_keccak.h" + +#include "lyra2/Lyra2.h" + +#include "miner.h" + +void lyra2_hash(void *state, const void *input) +{ + sph_blake256_context ctx_blake; + sph_keccak256_context ctx_keccak; + sph_skein256_context ctx_skein; + sph_groestl256_context ctx_groestl; + + uint32_t hashA[8], hashB[8]; + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hashA); + + sph_keccak256_init(&ctx_keccak); + sph_keccak256(&ctx_keccak, hashA, 32); + sph_keccak256_close(&ctx_keccak, hashB); + + LYRA2(hashA, 32, hashB, 32, hashB, 32, 1, 8, 8); + + sph_skein256_init(&ctx_skein); + sph_skein256(&ctx_skein, hashA, 32); + sph_skein256_close(&ctx_skein, hashB); + + sph_groestl256_init(&ctx_groestl); + sph_groestl256(&ctx_groestl, hashB, 32); + sph_groestl256_close(&ctx_groestl, hashA); + + memcpy(state, hashA, 32); +} + +int scanhash_lyra2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x0000ff; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], nonce); + lyra2_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/lyra2rev2.c b/algo/lyra2rev2.c new file mode 100644 index 000000000..b264ac36b --- /dev/null +++ b/algo/lyra2rev2.c @@ -0,0 +1,87 @@ +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_bmw.h" + +#include "lyra2/Lyra2.h" + +#include "miner.h" + +void lyra2rev2_hash(void *state, const void *input) +{ + uint32_t _ALIGN(128) hashA[8], hashB[8]; + + sph_blake256_context ctx_blake; + sph_keccak256_context ctx_keccak; + sph_cubehash256_context ctx_cubehash; + sph_skein256_context ctx_skein; + sph_bmw256_context ctx_bmw; + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hashA); + + sph_keccak256_init(&ctx_keccak); + sph_keccak256(&ctx_keccak, hashA, 32); + sph_keccak256_close(&ctx_keccak, hashB); + + sph_cubehash256_init(&ctx_cubehash); + sph_cubehash256(&ctx_cubehash, hashB, 32); + sph_cubehash256_close(&ctx_cubehash, hashA); + + LYRA2(hashB, 32, hashA, 32, hashA, 32, 1, 4, 4); + + sph_skein256_init(&ctx_skein); + sph_skein256(&ctx_skein, hashB, 32); + sph_skein256_close(&ctx_skein, hashA); + + sph_cubehash256_init(&ctx_cubehash); + sph_cubehash256(&ctx_cubehash, hashA, 32); + sph_cubehash256_close(&ctx_cubehash, hashB); + + sph_bmw256_init(&ctx_bmw); + sph_bmw256(&ctx_bmw, hashB, 32); + sph_bmw256_close(&ctx_bmw, hashA); + + memcpy(state, hashA, 32); +} + +int scanhash_lyra2rev2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x0000ff; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], nonce); + lyra2rev2_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/lyra2v3.c b/algo/lyra2v3.c new file mode 100644 index 000000000..4f18a5fa9 --- /dev/null +++ b/algo/lyra2v3.c @@ -0,0 +1,75 @@ +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_bmw.h" + +#include "lyra2/Lyra2.h" + +#include "miner.h" + +void lyra2v3_hash(void *state, const void *input) +{ + uint32_t _ALIGN(128) hash[8], hashB[8]; + + sph_blake256_context ctx_blake; + sph_cubehash256_context ctx_cubehash; + sph_bmw256_context ctx_bmw; + + //sph_blake256_set_rounds(14); + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, 80); + sph_blake256_close(&ctx_blake, hash); + + LYRA2_3(hashB, 32, hash, 32, hash, 32, 1, 4, 4); + + sph_cubehash256_init(&ctx_cubehash); + sph_cubehash256(&ctx_cubehash, hashB, 32); + sph_cubehash256_close(&ctx_cubehash, hash); + + LYRA2_3(hashB, 32, hash, 32, hash, 32, 1, 4, 4); + + sph_bmw256_init(&ctx_bmw); + sph_bmw256(&ctx_bmw, hashB, 32); + sph_bmw256_close(&ctx_bmw, hash); + + memcpy(state, hash, 32); +} + +int scanhash_lyra2v3(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x0000ff; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], nonce); + lyra2v3_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/myr-groestl.c b/algo/myr-groestl.c new file mode 100644 index 000000000..80ff70c03 --- /dev/null +++ b/algo/myr-groestl.c @@ -0,0 +1,65 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_groestl.h" +#include "sha3/sph_sha2.h" + +void myriadhash(void *output, const void *input) +{ + uint32_t _ALIGN(32) hash[16]; + sph_groestl512_context ctx; + sph_sha256_context sha_ctx; + + // memset(&hash[0], 0, sizeof(hash)); + + sph_groestl512_init(&ctx); + sph_groestl512(&ctx, input, 80); + sph_groestl512_close(&ctx, hash); + + sph_sha256_init(&sha_ctx); + sph_sha256(&sha_ctx, hash, 64); + sph_sha256_close(&sha_ctx, hash); + + memcpy(output, hash, 32); +} + +int scanhash_myriad(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x0000ff; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], nonce); + myriadhash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/neoscrypt.c b/algo/neoscrypt.c new file mode 100644 index 000000000..131143bbb --- /dev/null +++ b/algo/neoscrypt.c @@ -0,0 +1,1061 @@ +/* + * Copyright (c) 2009 Colin Percival, 2011 ArtForz + * Copyright (c) 2012 Andrew Moon (floodyberry) + * Copyright (c) 2012 Samuel Neves + * Copyright (c) 2014 John Doering + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include + +#include "miner.h" + +#define USE_CUSTOM_BLAKE2S +// TODO: try blake2sp +//#include "crypto/blake2s.h" + +#define STACK_ALIGN 0x40 + +#ifdef _MSC_VER // todo: msvc +#define ASM 0 +#elif defined(__arm__) +#define ASM 0 +#endif + +#ifdef __GNUC__ +#if defined(NOASM) || defined(__arm__) +#define ASM 0 +#else +#define ASM 1 +#endif +#endif + +#if (WINDOWS) +/* sizeof(unsigned long) = 4 for MinGW64 */ +typedef unsigned long long ulong; +#else +typedef unsigned long ulong; +#endif +typedef unsigned int uint; + + +#define MIN(a, b) ((a) < (b) ? a : b) +#define MAX(a, b) ((a) > (b) ? a : b) + +#define SCRYPT_BLOCK_SIZE 64U +#define SCRYPT_HASH_BLOCK_SIZE 64U +#define SCRYPT_HASH_DIGEST_SIZE 32U + +#define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b))) +#define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b))) + +#define U8TO32_BE(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ + ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]))) + +#define U32TO8_BE(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); + +#define U64TO8_BE(p, v) \ + U32TO8_BE((p), (uint32_t)((v) >> 32)); \ + U32TO8_BE((p) + 4, (uint32_t)((v) )); + + +typedef uint8_t hash_digest[SCRYPT_HASH_DIGEST_SIZE]; + + +/* SHA-256 */ + +static const uint32_t sha256_constants[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S0(x) (ROTR32(x, 2) ^ ROTR32(x, 13) ^ ROTR32(x, 22)) +#define S1(x) (ROTR32(x, 6) ^ ROTR32(x, 11) ^ ROTR32(x, 25)) +#define G0(x) (ROTR32(x, 7) ^ ROTR32(x, 18) ^ (x >> 3)) +#define G1(x) (ROTR32(x, 17) ^ ROTR32(x, 19) ^ (x >> 10)) +#define W0(in,i) (U8TO32_BE(&in[i * 4])) +#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16]) +#define STEP(i) \ + t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \ + t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha256_constants[i] + w[i]; \ + r[7] = r[6]; \ + r[6] = r[5]; \ + r[5] = r[4]; \ + r[4] = r[3] + t0; \ + r[3] = r[2]; \ + r[2] = r[1]; \ + r[1] = r[0]; \ + r[0] = t0 + t1; + + +typedef struct sha256_hash_state_t { + uint32_t H[8]; + uint64_t T; + uint32_t leftover; + uint8_t buffer[SCRYPT_HASH_BLOCK_SIZE]; +} sha256_hash_state; + + +static void sha256_blocks(sha256_hash_state *S, const uint8_t *in, size_t blocks) { + uint32_t r[8], w[64], t0, t1; + size_t i; + + for(i = 0; i < 8; i++) + r[i] = S->H[i]; + + while(blocks--) { + for(i = 0; i < 16; i++) { + w[i] = W0(in, i); + } + for(i = 16; i < 64; i++) { + w[i] = W1(i); + } + for(i = 0; i < 64; i++) { + STEP(i); + } + for(i = 0; i < 8; i++) { + r[i] += S->H[i]; + S->H[i] = r[i]; + } + S->T += SCRYPT_HASH_BLOCK_SIZE * 8; + in += SCRYPT_HASH_BLOCK_SIZE; + } +} + +static void neoscrypt_hash_init_sha256(sha256_hash_state *S) { + S->H[0] = 0x6a09e667; + S->H[1] = 0xbb67ae85; + S->H[2] = 0x3c6ef372; + S->H[3] = 0xa54ff53a; + S->H[4] = 0x510e527f; + S->H[5] = 0x9b05688c; + S->H[6] = 0x1f83d9ab; + S->H[7] = 0x5be0cd19; + S->T = 0; + S->leftover = 0; +} + +static void neoscrypt_hash_update_sha256(sha256_hash_state *S, const uint8_t *in, size_t inlen) { + size_t blocks, want; + + /* handle the previous data */ + if(S->leftover) { + want = (SCRYPT_HASH_BLOCK_SIZE - S->leftover); + want = (want < inlen) ? want : inlen; + memcpy(S->buffer + S->leftover, in, want); + S->leftover += (uint32_t)want; + if(S->leftover < SCRYPT_HASH_BLOCK_SIZE) + return; + in += want; + inlen -= want; + sha256_blocks(S, S->buffer, 1); + } + + /* handle the current data */ + blocks = (inlen & ~(SCRYPT_HASH_BLOCK_SIZE - 1)); + S->leftover = (uint32_t)(inlen - blocks); + if(blocks) { + sha256_blocks(S, in, blocks / SCRYPT_HASH_BLOCK_SIZE); + in += blocks; + } + + /* handle leftover data */ + if(S->leftover) + memcpy(S->buffer, in, S->leftover); +} + +static void neoscrypt_hash_finish_sha256(sha256_hash_state *S, uint8_t *hash) { + uint64_t t = S->T + (S->leftover * 8); + + S->buffer[S->leftover] = 0x80; + if(S->leftover <= 55) { + memset(S->buffer + S->leftover + 1, 0, 55 - S->leftover); + } else { + memset(S->buffer + S->leftover + 1, 0, 63 - S->leftover); + sha256_blocks(S, S->buffer, 1); + memset(S->buffer, 0, 56); + } + + U64TO8_BE(S->buffer + 56, t); + sha256_blocks(S, S->buffer, 1); + + U32TO8_BE(&hash[ 0], S->H[0]); + U32TO8_BE(&hash[ 4], S->H[1]); + U32TO8_BE(&hash[ 8], S->H[2]); + U32TO8_BE(&hash[12], S->H[3]); + U32TO8_BE(&hash[16], S->H[4]); + U32TO8_BE(&hash[20], S->H[5]); + U32TO8_BE(&hash[24], S->H[6]); + U32TO8_BE(&hash[28], S->H[7]); +} + +static void neoscrypt_hash_sha256(hash_digest hash, const uint8_t *m, size_t mlen) { + sha256_hash_state st; + neoscrypt_hash_init_sha256(&st); + neoscrypt_hash_update_sha256(&st, m, mlen); + neoscrypt_hash_finish_sha256(&st, hash); +} + + +/* HMAC for SHA-256 */ + +typedef struct sha256_hmac_state_t { + sha256_hash_state inner, outer; +} sha256_hmac_state; + +static void neoscrypt_hmac_init_sha256(sha256_hmac_state *st, const uint8_t *key, size_t keylen) { + uint8_t pad[SCRYPT_HASH_BLOCK_SIZE] = {0}; + size_t i; + + neoscrypt_hash_init_sha256(&st->inner); + neoscrypt_hash_init_sha256(&st->outer); + + if(keylen <= SCRYPT_HASH_BLOCK_SIZE) { + /* use the key directly if it's <= blocksize bytes */ + memcpy(pad, key, keylen); + } else { + /* if it's > blocksize bytes, hash it */ + neoscrypt_hash_sha256(pad, key, keylen); + } + + /* inner = (key ^ 0x36) */ + /* h(inner || ...) */ + for(i = 0; i < SCRYPT_HASH_BLOCK_SIZE; i++) + pad[i] ^= 0x36; + neoscrypt_hash_update_sha256(&st->inner, pad, SCRYPT_HASH_BLOCK_SIZE); + + /* outer = (key ^ 0x5c) */ + /* h(outer || ...) */ + for(i = 0; i < SCRYPT_HASH_BLOCK_SIZE; i++) + pad[i] ^= (0x5c ^ 0x36); + neoscrypt_hash_update_sha256(&st->outer, pad, SCRYPT_HASH_BLOCK_SIZE); +} + +static void neoscrypt_hmac_update_sha256(sha256_hmac_state *st, const uint8_t *m, size_t mlen) { + /* h(inner || m...) */ + neoscrypt_hash_update_sha256(&st->inner, m, mlen); +} + +static void neoscrypt_hmac_finish_sha256(sha256_hmac_state *st, hash_digest mac) { + /* h(inner || m) */ + hash_digest innerhash; + neoscrypt_hash_finish_sha256(&st->inner, innerhash); + + /* h(outer || h(inner || m)) */ + neoscrypt_hash_update_sha256(&st->outer, innerhash, sizeof(innerhash)); + neoscrypt_hash_finish_sha256(&st->outer, mac); +} + + +/* PBKDF2 for SHA-256 */ + +static void neoscrypt_pbkdf2_sha256(const uint8_t *password, size_t password_len, + const uint8_t *salt, size_t salt_len, uint64_t N, uint8_t *output, size_t output_len) { + sha256_hmac_state hmac_pw, hmac_pw_salt, work; + hash_digest ti, u; + uint8_t be[4]; + uint32_t i, j, k, blocks; + + /* bytes must be <= (0xffffffff - (SCRYPT_HASH_DIGEST_SIZE - 1)), which they will always be under scrypt */ + + /* hmac(password, ...) */ + neoscrypt_hmac_init_sha256(&hmac_pw, password, password_len); + + /* hmac(password, salt...) */ + hmac_pw_salt = hmac_pw; + neoscrypt_hmac_update_sha256(&hmac_pw_salt, salt, salt_len); + + blocks = ((uint32_t)output_len + (SCRYPT_HASH_DIGEST_SIZE - 1)) / SCRYPT_HASH_DIGEST_SIZE; + for(i = 1; i <= blocks; i++) { + /* U1 = hmac(password, salt || be(i)) */ + U32TO8_BE(be, i); + work = hmac_pw_salt; + neoscrypt_hmac_update_sha256(&work, be, 4); + neoscrypt_hmac_finish_sha256(&work, ti); + memcpy(u, ti, sizeof(u)); + + /* T[i] = U1 ^ U2 ^ U3... */ + for(j = 0; j < N - 1; j++) { + /* UX = hmac(password, U{X-1}) */ + work = hmac_pw; + neoscrypt_hmac_update_sha256(&work, u, SCRYPT_HASH_DIGEST_SIZE); + neoscrypt_hmac_finish_sha256(&work, u); + + /* T[i] ^= UX */ + for(k = 0; k < sizeof(u); k++) + ti[k] ^= u[k]; + } + + memcpy(output, ti, (output_len > SCRYPT_HASH_DIGEST_SIZE) ? SCRYPT_HASH_DIGEST_SIZE : output_len); + output += SCRYPT_HASH_DIGEST_SIZE; + output_len -= SCRYPT_HASH_DIGEST_SIZE; + } +} + + +/* NeoScrypt */ + +#if (ASM) + +extern void neoscrypt_salsa(uint *X, uint rounds); +extern void neoscrypt_salsa_tangle(uint *X, uint count); +extern void neoscrypt_chacha(uint *X, uint rounds); + +extern void neoscrypt_blkcpy(void *dstp, const void *srcp, uint len); +extern void neoscrypt_blkswp(void *blkAp, void *blkBp, uint len); +extern void neoscrypt_blkxor(void *dstp, const void *srcp, uint len); + +#else + +/* Salsa20, rounds must be a multiple of 2 */ +static void neoscrypt_salsa(uint *X, uint rounds) { + uint x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, t; + + x0 = X[0]; x1 = X[1]; x2 = X[2]; x3 = X[3]; + x4 = X[4]; x5 = X[5]; x6 = X[6]; x7 = X[7]; + x8 = X[8]; x9 = X[9]; x10 = X[10]; x11 = X[11]; + x12 = X[12]; x13 = X[13]; x14 = X[14]; x15 = X[15]; + +#define quarter(a, b, c, d) \ + t = a + d; t = ROTL32(t, 7); b ^= t; \ + t = b + a; t = ROTL32(t, 9); c ^= t; \ + t = c + b; t = ROTL32(t, 13); d ^= t; \ + t = d + c; t = ROTL32(t, 18); a ^= t; + + for(; rounds; rounds -= 2) { + quarter( x0, x4, x8, x12); + quarter( x5, x9, x13, x1); + quarter(x10, x14, x2, x6); + quarter(x15, x3, x7, x11); + quarter( x0, x1, x2, x3); + quarter( x5, x6, x7, x4); + quarter(x10, x11, x8, x9); + quarter(x15, x12, x13, x14); + } + + X[0] += x0; X[1] += x1; X[2] += x2; X[3] += x3; + X[4] += x4; X[5] += x5; X[6] += x6; X[7] += x7; + X[8] += x8; X[9] += x9; X[10] += x10; X[11] += x11; + X[12] += x12; X[13] += x13; X[14] += x14; X[15] += x15; + +#undef quarter +} + +/* ChaCha20, rounds must be a multiple of 2 */ +static void neoscrypt_chacha(uint *X, uint rounds) { + uint x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, t; + + x0 = X[0]; x1 = X[1]; x2 = X[2]; x3 = X[3]; + x4 = X[4]; x5 = X[5]; x6 = X[6]; x7 = X[7]; + x8 = X[8]; x9 = X[9]; x10 = X[10]; x11 = X[11]; + x12 = X[12]; x13 = X[13]; x14 = X[14]; x15 = X[15]; + +#define quarter(a,b,c,d) \ + a += b; t = d ^ a; d = ROTL32(t, 16); \ + c += d; t = b ^ c; b = ROTL32(t, 12); \ + a += b; t = d ^ a; d = ROTL32(t, 8); \ + c += d; t = b ^ c; b = ROTL32(t, 7); + + for(; rounds; rounds -= 2) { + quarter( x0, x4, x8, x12); + quarter( x1, x5, x9, x13); + quarter( x2, x6, x10, x14); + quarter( x3, x7, x11, x15); + quarter( x0, x5, x10, x15); + quarter( x1, x6, x11, x12); + quarter( x2, x7, x8, x13); + quarter( x3, x4, x9, x14); + } + + X[0] += x0; X[1] += x1; X[2] += x2; X[3] += x3; + X[4] += x4; X[5] += x5; X[6] += x6; X[7] += x7; + X[8] += x8; X[9] += x9; X[10] += x10; X[11] += x11; + X[12] += x12; X[13] += x13; X[14] += x14; X[15] += x15; + +#undef quarter +} + + +/* Fast 32-bit / 64-bit memcpy(); + * len must be a multiple of 32 bytes */ +static void neoscrypt_blkcpy(void *dstp, const void *srcp, uint len) { + ulong *dst = (ulong *) dstp; + ulong *src = (ulong *) srcp; + uint i; + + for(i = 0; i < (len / sizeof(ulong)); i += 4) { + dst[i] = src[i]; + dst[i + 1] = src[i + 1]; + dst[i + 2] = src[i + 2]; + dst[i + 3] = src[i + 3]; + } +} + +/* Fast 32-bit / 64-bit block swapper; + * len must be a multiple of 32 bytes */ +static void neoscrypt_blkswp(void *blkAp, void *blkBp, uint len) { + ulong *blkA = (ulong *) blkAp; + ulong *blkB = (ulong *) blkBp; + register ulong t0, t1, t2, t3; + uint i; + + for(i = 0; i < (len / sizeof(ulong)); i += 4) { + t0 = blkA[i]; + t1 = blkA[i + 1]; + t2 = blkA[i + 2]; + t3 = blkA[i + 3]; + blkA[i] = blkB[i]; + blkA[i + 1] = blkB[i + 1]; + blkA[i + 2] = blkB[i + 2]; + blkA[i + 3] = blkB[i + 3]; + blkB[i] = t0; + blkB[i + 1] = t1; + blkB[i + 2] = t2; + blkB[i + 3] = t3; + } +} + +/* Fast 32-bit / 64-bit block XOR engine; + * len must be a multiple of 32 bytes */ +static void neoscrypt_blkxor(void *dstp, const void *srcp, uint len) { + ulong *dst = (ulong *) dstp; + ulong *src = (ulong *) srcp; + uint i; + + for(i = 0; i < (len / sizeof(ulong)); i += 4) { + dst[i] ^= src[i]; + dst[i + 1] ^= src[i + 1]; + dst[i + 2] ^= src[i + 2]; + dst[i + 3] ^= src[i + 3]; + } +} + +#endif + +/* 32-bit / 64-bit optimised memcpy() */ +static void neoscrypt_copy(void *dstp, const void *srcp, uint len) { + ulong *dst = (ulong *) dstp; + ulong *src = (ulong *) srcp; + uint i, tail; + + for(i = 0; i < (len / sizeof(ulong)); i++) + dst[i] = src[i]; + + tail = len & (sizeof(ulong) - 1); + if(tail) { + uchar *dstb = (uchar *) dstp; + uchar *srcb = (uchar *) srcp; + + for(i = len - tail; i < len; i++) + dstb[i] = srcb[i]; + } +} + +/* 32-bit / 64-bit optimised memory erase aka memset() to zero */ +static void neoscrypt_erase(void *dstp, uint len) { + const ulong null = 0; + ulong *dst = (ulong *) dstp; + uint i, tail; + + for(i = 0; i < (len / sizeof(ulong)); i++) + dst[i] = null; + + tail = len & (sizeof(ulong) - 1); + if(tail) { + uchar *dstb = (uchar *) dstp; + + for(i = len - tail; i < len; i++) + dstb[i] = (uchar)null; + } +} + +/* 32-bit / 64-bit optimised XOR engine */ +static void neoscrypt_xor(void *dstp, const void *srcp, uint len) { + ulong *dst = (ulong *) dstp; + ulong *src = (ulong *) srcp; + uint i, tail; + + for(i = 0; i < (len / sizeof(ulong)); i++) + dst[i] ^= src[i]; + + tail = len & (sizeof(ulong) - 1); + if(tail) { + uchar *dstb = (uchar *) dstp; + uchar *srcb = (uchar *) srcp; + + for(i = len - tail; i < len; i++) + dstb[i] ^= srcb[i]; + } +} + +/* BLAKE2s */ + +#define BLAKE2S_BLOCK_SIZE 64U +#define BLAKE2S_OUT_SIZE 32U +#define BLAKE2S_KEY_SIZE 32U + +static const uint blake2s_IV[8] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +#ifdef USE_CUSTOM_BLAKE2S + +static const uint8_t blake2s_sigma[10][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +/* Parameter block of 32 bytes */ +typedef struct blake2s_param_t { + uchar digest_length; + uchar key_length; + uchar fanout; + uchar depth; + uint leaf_length; + uchar node_offset[6]; + uchar node_depth; + uchar inner_length; + uchar salt[8]; + uchar personal[8]; +} blake2s_param; + +/* State block of 180 bytes */ +typedef struct blake2s_state_t { + uint h[8]; + uint t[2]; + uint f[2]; + uchar buf[2 * BLAKE2S_BLOCK_SIZE]; + uint buflen; +} blake2s_state; + +static void blake2s_compress(blake2s_state *S, const void *buf) { + uint i; + uint m[16]; + uint v[16]; + + neoscrypt_copy(m, buf, 64); + neoscrypt_copy(v, S, 32); + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = ROTR32(d ^ a, 16); \ + c = c + d; \ + b = ROTR32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = ROTR32(d ^ a, 8); \ + c = c + d; \ + b = ROTR32(b ^ c, 7); \ + } while(0) +#define ROUND(r) \ + do { \ + G(r, 0, v[ 0], v[ 4], v[ 8], v[12]); \ + G(r, 1, v[ 1], v[ 5], v[ 9], v[13]); \ + G(r, 2, v[ 2], v[ 6], v[10], v[14]); \ + G(r, 3, v[ 3], v[ 7], v[11], v[15]); \ + G(r, 4, v[ 0], v[ 5], v[10], v[15]); \ + G(r, 5, v[ 1], v[ 6], v[11], v[12]); \ + G(r, 6, v[ 2], v[ 7], v[ 8], v[13]); \ + G(r, 7, v[ 3], v[ 4], v[ 9], v[14]); \ + } while(0) + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + + for(i = 0; i < 8; i++) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + +#undef G +#undef ROUND +} + +static void blake2s_update(blake2s_state *S, const uchar *input, uint input_size) { + uint left, fill; + + while(input_size > 0) { + left = S->buflen; + fill = 2 * BLAKE2S_BLOCK_SIZE - left; + if(input_size > fill) { + /* Buffer fill */ + neoscrypt_copy(S->buf + left, input, fill); + S->buflen += fill; + /* Counter increment */ + S->t[0] += BLAKE2S_BLOCK_SIZE; + /* Compress */ + blake2s_compress(S, (void *) S->buf); + /* Shift buffer left */ + neoscrypt_copy(S->buf, S->buf + BLAKE2S_BLOCK_SIZE, BLAKE2S_BLOCK_SIZE); + S->buflen -= BLAKE2S_BLOCK_SIZE; + input += fill; + input_size -= fill; + } else { + neoscrypt_copy(S->buf + left, input, input_size); + S->buflen += input_size; + /* Do not compress */ + input += input_size; + input_size = 0; + } + } +} +#endif + +static void neoscrypt_blake2s(const void *input, const uint input_size, const void *key, const uchar key_size, + void *output, const uchar output_size) { + uchar block[BLAKE2S_BLOCK_SIZE]; + blake2s_param P[1]; + blake2s_state S[1]; + + /* Initialise */ + neoscrypt_erase(P, 32); + P->digest_length = output_size; + P->key_length = key_size; + P->fanout = 1; + P->depth = 1; + + neoscrypt_erase(S, 180); + neoscrypt_copy(S, blake2s_IV, 32); + neoscrypt_xor(S, P, 32); + + neoscrypt_erase(block, BLAKE2S_BLOCK_SIZE); + neoscrypt_copy(block, key, key_size); + blake2s_update(S, (uchar *) block, BLAKE2S_BLOCK_SIZE); + + /* Update */ + blake2s_update(S, (uchar *) input, input_size); + + /* Finish */ + if(S->buflen > BLAKE2S_BLOCK_SIZE) { + S->t[0] += BLAKE2S_BLOCK_SIZE; + blake2s_compress(S, (void *) S->buf); + S->buflen -= BLAKE2S_BLOCK_SIZE; + neoscrypt_copy(S->buf, S->buf + BLAKE2S_BLOCK_SIZE, S->buflen); + } + S->t[0] += S->buflen; + S->f[0] = ~0U; + neoscrypt_erase(S->buf + S->buflen, 2 * BLAKE2S_BLOCK_SIZE - S->buflen); + blake2s_compress(S, (void *) S->buf); + + /* Write back */ + neoscrypt_copy(output, S, output_size); +} + + +#define FASTKDF_BUFFER_SIZE 256U + +/* FastKDF, a fast buffered key derivation function: + * FASTKDF_BUFFER_SIZE must be a power of 2; + * password_len, salt_len and output_len should not exceed FASTKDF_BUFFER_SIZE; + * prf_output_size must be <= prf_key_size; */ +static void neoscrypt_fastkdf(const uchar *password, uint password_len, const uchar *salt, uint salt_len, + uint N, uchar *output, uint output_len) { + +#define kdf_buf_size FASTKDF_BUFFER_SIZE +#define prf_input_size BLAKE2S_BLOCK_SIZE +#define prf_key_size BLAKE2S_KEY_SIZE +#define prf_output_size BLAKE2S_OUT_SIZE + + uint bufptr, a, b, i, j; + uchar *A, *B, *prf_input, *prf_key, *prf_output; + + /* Align and set up the buffers in stack */ + uchar stack[2 * kdf_buf_size + prf_input_size + prf_key_size + prf_output_size + STACK_ALIGN]; + A = &stack[STACK_ALIGN & ~(STACK_ALIGN - 1)]; + B = &A[kdf_buf_size + prf_input_size]; + prf_output = &A[2 * kdf_buf_size + prf_input_size + prf_key_size]; + + /* Initialise the password buffer */ + if(password_len > kdf_buf_size) + password_len = kdf_buf_size; + + a = kdf_buf_size / password_len; + for(i = 0; i < a; i++) + neoscrypt_copy(&A[i * password_len], &password[0], password_len); + b = kdf_buf_size - a * password_len; + if(b) + neoscrypt_copy(&A[a * password_len], &password[0], b); + neoscrypt_copy(&A[kdf_buf_size], &password[0], prf_input_size); + + /* Initialise the salt buffer */ + if(salt_len > kdf_buf_size) + salt_len = kdf_buf_size; + + a = kdf_buf_size / salt_len; + for(i = 0; i < a; i++) + neoscrypt_copy(&B[i * salt_len], &salt[0], salt_len); + b = kdf_buf_size - a * salt_len; + if(b) + neoscrypt_copy(&B[a * salt_len], &salt[0], b); + neoscrypt_copy(&B[kdf_buf_size], &salt[0], prf_key_size); + + /* The primary iteration */ + for(i = 0, bufptr = 0; i < N; i++) { + + /* Map the PRF input buffer */ + prf_input = &A[bufptr]; + + /* Map the PRF key buffer */ + prf_key = &B[bufptr]; + + /* PRF */ + neoscrypt_blake2s(prf_input, prf_input_size, prf_key, prf_key_size, prf_output, prf_output_size); + + /* Calculate the next buffer pointer */ + for(j = 0, bufptr = 0; j < prf_output_size; j++) + bufptr += prf_output[j]; + bufptr &= (kdf_buf_size - 1); + + /* Modify the salt buffer */ + neoscrypt_xor(&B[bufptr], &prf_output[0], prf_output_size); + + /* Head modified, tail updated */ + if(bufptr < prf_key_size) + neoscrypt_copy(&B[kdf_buf_size + bufptr], &B[bufptr], MIN(prf_output_size, prf_key_size - bufptr)); + + /* Tail modified, head updated */ + if((kdf_buf_size - bufptr) < prf_output_size) + neoscrypt_copy(&B[0], &B[kdf_buf_size], prf_output_size - (kdf_buf_size - bufptr)); + + } + + /* Modify and copy into the output buffer */ + if(output_len > kdf_buf_size) + output_len = kdf_buf_size; + + a = kdf_buf_size - bufptr; + if(a >= output_len) { + neoscrypt_xor(&B[bufptr], &A[0], output_len); + neoscrypt_copy(&output[0], &B[bufptr], output_len); + } else { + neoscrypt_xor(&B[bufptr], &A[0], a); + neoscrypt_xor(&B[0], &A[a], output_len - a); + neoscrypt_copy(&output[0], &B[bufptr], a); + neoscrypt_copy(&output[a], &B[0], output_len - a); + } + +} + + +/* Configurable optimised block mixer */ +static void neoscrypt_blkmix(uint *X, uint *Y, uint r, uint mixmode) { + uint i, mixer, rounds; + + mixer = mixmode >> 8; + rounds = mixmode & 0xFF; + + /* NeoScrypt flow: Scrypt flow: + Xa ^= Xd; M(Xa'); Ya = Xa"; Xa ^= Xb; M(Xa'); Ya = Xa"; + Xb ^= Xa"; M(Xb'); Yb = Xb"; Xb ^= Xa"; M(Xb'); Yb = Xb"; + Xc ^= Xb"; M(Xc'); Yc = Xc"; Xa" = Ya; + Xd ^= Xc"; M(Xd'); Yd = Xd"; Xb" = Yb; + Xa" = Ya; Xb" = Yc; + Xc" = Yb; Xd" = Yd; */ + + if(r == 1) { + neoscrypt_blkxor(&X[0], &X[16], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[0], rounds); + else + neoscrypt_salsa(&X[0], rounds); + neoscrypt_blkxor(&X[16], &X[0], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[16], rounds); + else + neoscrypt_salsa(&X[16], rounds); + return; + } + + if(r == 2) { + neoscrypt_blkxor(&X[0], &X[48], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[0], rounds); + else + neoscrypt_salsa(&X[0], rounds); + neoscrypt_blkxor(&X[16], &X[0], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[16], rounds); + else + neoscrypt_salsa(&X[16], rounds); + neoscrypt_blkxor(&X[32], &X[16], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[32], rounds); + else + neoscrypt_salsa(&X[32], rounds); + neoscrypt_blkxor(&X[48], &X[32], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[48], rounds); + else + neoscrypt_salsa(&X[48], rounds); + neoscrypt_blkswp(&X[16], &X[32], SCRYPT_BLOCK_SIZE); + return; + } + + /* Reference code for any reasonable r */ + for(i = 0; i < 2 * r; i++) { + if(i) neoscrypt_blkxor(&X[16 * i], &X[16 * (i - 1)], SCRYPT_BLOCK_SIZE); + else neoscrypt_blkxor(&X[0], &X[16 * (2 * r - 1)], SCRYPT_BLOCK_SIZE); + if(mixer) + neoscrypt_chacha(&X[16 * i], rounds); + else + neoscrypt_salsa(&X[16 * i], rounds); + neoscrypt_blkcpy(&Y[16 * i], &X[16 * i], SCRYPT_BLOCK_SIZE); + } + for(i = 0; i < r; i++) + neoscrypt_blkcpy(&X[16 * i], &Y[16 * 2 * i], SCRYPT_BLOCK_SIZE); + for(i = 0; i < r; i++) + neoscrypt_blkcpy(&X[16 * (i + r)], &Y[16 * (2 * i + 1)], SCRYPT_BLOCK_SIZE); +} + +/* NeoScrypt core engine: + * p = 1, salt = password; + * Basic customisation (required): + * profile bit 0: + * 0 = NeoScrypt(128, 2, 1) with Salsa20/20 and ChaCha20/20; + * 1 = Scrypt(1024, 1, 1) with Salsa20/8; + * profile bits 4 to 1: + * 0000 = FastKDF-BLAKE2s; + * 0001 = PBKDF2-HMAC-SHA256; + * Extended customisation (optional): + * profile bit 31: + * 0 = extended customisation absent; + * 1 = extended customisation present; + * profile bits 7 to 5 (rfactor): + * 000 = r of 1; + * 001 = r of 2; + * 010 = r of 4; + * ... + * 111 = r of 128; + * profile bits 12 to 8 (Nfactor): + * 00000 = N of 2; + * 00001 = N of 4; + * 00010 = N of 8; + * ..... + * 00110 = N of 128; + * ..... + * 01001 = N of 1024; + * ..... + * 11110 = N of 2147483648; + * profile bits 30 to 13 are reserved */ +void neoscrypt(uchar *output, const uchar *password, uint32_t profile) +{ + uint N = 128, r = 2, dblmix = 1, mixmode = 0x14; + uint kdf, i, j; + uint *X, *Y, *Z, *V; + + if(profile & 0x1) { + N = 1024; /* N = (1 << (Nfactor + 1)); */ + r = 1; /* r = (1 << rfactor); */ + dblmix = 0; /* Salsa only */ + mixmode = 0x08; /* 8 rounds */ + } + + if(profile >> 31) { + N = (1 << (((profile >> 8) & 0x1F) + 1)); + r = (1 << ((profile >> 5) & 0x7)); + } + + uchar *stack = (uchar*) malloc((N + 3) * r * 2 * SCRYPT_BLOCK_SIZE + STACK_ALIGN); + /* X = r * 2 * SCRYPT_BLOCK_SIZE */ + X = (uint *) &stack[STACK_ALIGN & ~(STACK_ALIGN - 1)]; + /* Z is a copy of X for ChaCha */ + Z = &X[32 * r]; + /* Y is an X sized temporal space */ + Y = &X[64 * r]; + /* V = N * r * 2 * SCRYPT_BLOCK_SIZE */ + V = &X[96 * r]; + + /* X = KDF(password, salt) */ + kdf = (profile >> 1) & 0xF; + + switch(kdf) { + + default: + case(0x0): + neoscrypt_fastkdf(password, 80, password, 80, 32, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE); + break; + + case(0x1): + neoscrypt_pbkdf2_sha256(password, 80, password, 80, 1, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE); + break; + + } + + /* Process ChaCha 1st, Salsa 2nd and XOR them into FastKDF; otherwise Salsa only */ + + if(dblmix) { + /* blkcpy(Z, X) */ + neoscrypt_blkcpy(&Z[0], &X[0], r * 2 * SCRYPT_BLOCK_SIZE); + + /* Z = SMix(Z) */ + for(i = 0; i < N; i++) { + /* blkcpy(V, Z) */ + neoscrypt_blkcpy(&V[i * (32 * r)], &Z[0], r * 2 * SCRYPT_BLOCK_SIZE); + /* blkmix(Z, Y) */ + neoscrypt_blkmix(&Z[0], &Y[0], r, (mixmode | 0x0100)); + } + for(i = 0; i < N; i++) { + /* integerify(Z) mod N */ + j = (32 * r) * (Z[16 * (2 * r - 1)] & (N - 1)); + /* blkxor(Z, V) */ + neoscrypt_blkxor(&Z[0], &V[j], r * 2 * SCRYPT_BLOCK_SIZE); + /* blkmix(Z, Y) */ + neoscrypt_blkmix(&Z[0], &Y[0], r, (mixmode | 0x0100)); + } + } + +#if (ASM) + /* Must be called before and after SSE2 Salsa */ + neoscrypt_salsa_tangle(&X[0], r * 2); +#endif + + /* X = SMix(X) */ + for(i = 0; i < N; i++) { + /* blkcpy(V, X) */ + neoscrypt_blkcpy(&V[i * (32 * r)], &X[0], r * 2 * SCRYPT_BLOCK_SIZE); + /* blkmix(X, Y) */ + neoscrypt_blkmix(&X[0], &Y[0], r, mixmode); + } + for(i = 0; i < N; i++) { + /* integerify(X) mod N */ + j = (32 * r) * (X[16 * (2 * r - 1)] & (N - 1)); + /* blkxor(X, V) */ + neoscrypt_blkxor(&X[0], &V[j], r * 2 * SCRYPT_BLOCK_SIZE); + /* blkmix(X, Y) */ + neoscrypt_blkmix(&X[0], &Y[0], r, mixmode); + } + +#if (ASM) + neoscrypt_salsa_tangle(&X[0], r * 2); +#endif + + if(dblmix) + /* blkxor(X, Z) */ + neoscrypt_blkxor(&X[0], &Z[0], r * 2 * SCRYPT_BLOCK_SIZE); + + /* output = KDF(password, X) */ + switch(kdf) { + default: + case(0x0): + neoscrypt_fastkdf(password, 80, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE, 32, output, 32); + break; + + case(0x1): + neoscrypt_pbkdf2_sha256(password, 80, (uchar *) X, r * 2 * SCRYPT_BLOCK_SIZE, 1, output, 32); + break; + } + + free(stack); +} + +static bool fulltest_le(const uint *hash, const uint *target) +{ + bool rc = false; + + for (int i = 7; i >= 0; i--) { + if (hash[i] > target[i]) { + rc = false; + break; + } + if(hash[i] < target[i]) { + rc = true; + break; + } + } + + if (opt_debug) { + uchar hash_str[65], target_str[65]; + + bin2hex(hash_str, (uint8_t *) hash, 32); + bin2hex(target_str, (uint8_t *) target, 32); + + applog(LOG_DEBUG, "DEBUG (little endian): %s\nHash: %sx0\nTarget: %sx0", + rc ? "hash <= target" : "hash > target (false positive)", + hash_str, target_str); + } + + return(rc); +} + +int scanhash_neoscrypt(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, + uint32_t profile) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + while (pdata[19] < max_nonce && !work_restart[thr_id].restart) + { + neoscrypt((uint8_t *) hash, (uint8_t *) pdata, profile); + + /* Quick hash check */ + if (hash[7] <= Htarg && fulltest_le(hash, ptarget)) { + work_set_target_ratio(work, hash); + *hashes_done = pdata[19] - first_nonce + 1; + return 1; + } + + pdata[19]++; + } + + *hashes_done = pdata[19] - first_nonce; + return 0; +} diff --git a/algo/nist5.c b/algo/nist5.c new file mode 100644 index 000000000..6fb7fef47 --- /dev/null +++ b/algo/nist5.c @@ -0,0 +1,115 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" + +void nist5hash(void *output, const void *input) +{ + sph_blake512_context ctx_blake; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + + uint8_t hash[64]; + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, (void*) hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, (const void*) hash, 64); + sph_groestl512_close(&ctx_groestl, (void*) hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, (const void*) hash, 64); + sph_jh512_close(&ctx_jh, (void*) hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, (const void*) hash, 64); + sph_keccak512_close(&ctx_keccak, (void*) hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, (const void*) hash, 64); + sph_skein512_close(&ctx_skein, (void*) hash); + + memcpy(output, hash, 32); +} + +int scanhash_nist5(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + uint32_t n = pdata[19] - 1; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + nist5hash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/pentablake.c b/algo/pentablake.c new file mode 100644 index 000000000..d69e5970c --- /dev/null +++ b/algo/pentablake.c @@ -0,0 +1,109 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_blake.h" + +//#define DEBUG_ALGO + +extern void pentablakehash(void *output, const void *input) +{ + unsigned char _ALIGN(32) hash[128]; + // same as uint32_t hashA[16], hashB[16]; + #define hashB hash+64 + + sph_blake512_context ctx_blake; + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, hash); + + sph_blake512(&ctx_blake, hash, 64); + sph_blake512_close(&ctx_blake, hashB); + + sph_blake512(&ctx_blake, hashB, 64); + sph_blake512_close(&ctx_blake, hash); + + sph_blake512(&ctx_blake, hash, 64); + sph_blake512_close(&ctx_blake, hashB); + + sph_blake512(&ctx_blake, hashB, 64); + sph_blake512_close(&ctx_blake, hash); + + memcpy(output, hash, 32); +} + +int scanhash_pentablake(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + uint32_t n = pdata[19] - 1; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + if (Htarg != 0) + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + pentablakehash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/phi1612.c b/algo/phi1612.c new file mode 100644 index 000000000..393a9822f --- /dev/null +++ b/algo/phi1612.c @@ -0,0 +1,91 @@ +/** + * Phi1612 algo Implementation (initial LUX algo) + */ + +#include + +#include "sha3/sph_skein.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_fugue.h" +#include "sha3/gost_streebog.h" +#include "sha3/sph_echo.h" + +#include "miner.h" + +void phi1612_hash(void *state, const void *input) +{ + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_cubehash512_context ctx_cubehash; + sph_fugue512_context ctx_fugue; + sph_gost512_context ctx_gost; + sph_echo512_context ctx_echo; + + uint8_t _ALIGN(128) hash[64]; + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, input, 80); + sph_skein512_close(&ctx_skein, (void*) hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, (const void*) hash, 64); + sph_jh512_close(&ctx_jh, (void*) hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, (const void*) hash, 64); + sph_cubehash512_close(&ctx_cubehash, (void*) hash); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, (const void*) hash, 64); + sph_fugue512_close(&ctx_fugue, (void*) hash); + + sph_gost512_init(&ctx_gost); + sph_gost512(&ctx_gost, (const void*) hash, 64); + sph_gost512_close(&ctx_gost, (void*) hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, (const void*) hash, 64); + sph_echo512_close(&ctx_echo, (void*) hash); + + memcpy(state, hash, 32); +} + +int scanhash_phi1612(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t n = first_nonce; + + if(opt_benchmark){ + ptarget[7] = 0x00ff; + } + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + phi1612_hash(hash, endiandata); + + if (hash[7] < Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/phi2.c b/algo/phi2.c new file mode 100644 index 000000000..cf05d2499 --- /dev/null +++ b/algo/phi2.c @@ -0,0 +1,106 @@ +/** + * Phi-2 algo Implementation + */ + +#include + +#include "sha3/sph_cubehash.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_jh.h" +//#include "sha3/sph_fugue.h" +#include "sha3/gost_streebog.h" +#include "sha3/sph_echo.h" + +#include "lyra2/Lyra2.h" + +#include "miner.h" + +static bool has_roots; + +void phi2_hash(void *state, const void *input) +{ + unsigned char _ALIGN(128) hash[64]; + unsigned char _ALIGN(128) hashA[64]; + unsigned char _ALIGN(128) hashB[64]; + + sph_cubehash512_context ctx_cubehash; + sph_jh512_context ctx_jh; + sph_gost512_context ctx_gost; + sph_echo512_context ctx_echo; + sph_skein512_context ctx_skein; + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, input, has_roots ? 144 : 80); + sph_cubehash512_close(&ctx_cubehash, (void*)hashB); + + LYRA2(&hashA[ 0], 32, &hashB[ 0], 32, &hashB[ 0], 32, 1, 8, 8); + LYRA2(&hashA[32], 32, &hashB[32], 32, &hashB[32], 32, 1, 8, 8); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, (const void*)hashA, 64); + sph_jh512_close(&ctx_jh, (void*)hash); + + if (hash[0] & 1) { + sph_gost512_init(&ctx_gost); + sph_gost512(&ctx_gost, (const void*)hash, 64); + sph_gost512_close(&ctx_gost, (void*)hash); + } else { + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, (const void*)hash, 64); + sph_echo512_close(&ctx_echo, (void*)hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, (const void*)hash, 64); + sph_echo512_close(&ctx_echo, (void*)hash); + } + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, (const void*)hash, 64); + sph_skein512_close(&ctx_skein, (void*)hash); + + for (int i=0; i<4; i++) + ((uint64_t*)hash)[i] ^= ((uint64_t*)hash)[i+4]; + + memcpy(state, hash, 32); +} + +int scanhash_phi2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[36]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t n = first_nonce; + + if(opt_benchmark){ + ptarget[7] = 0x00ff; + } + + has_roots = false; + for (int i=0; i < 36; i++) { + be32enc(&endiandata[i], pdata[i]); + if (i >= 20 && pdata[i]) has_roots = true; + } + + do { + be32enc(&endiandata[19], n); + phi2_hash(hash, endiandata); + + if (hash[7] < Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/pluck.c b/algo/pluck.c new file mode 100644 index 000000000..e0f03df92 --- /dev/null +++ b/algo/pluck.c @@ -0,0 +1,481 @@ +/* + * Copyright 2009 Colin Percival, 2011 ArtForz, 2011-2014 pooler, 2015 Jordan Earls + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cpuminer-config.h" +#include "miner.h" + +#include +#include + +#define BLOCK_HEADER_SIZE 80 + +// windows +#ifndef htobe32 +#define htobe32(x) ((uint32_t)htonl((uint32_t)(x))) +#endif + +#ifdef _MSC_VER +#define ROTL(a, b) _rotl(a,b) +#define ROTR(a, b) _rotr(a,b) +#else +#define ROTL(a, b) (((a) << b) | ((a) >> (32 - b))) +#define ROTR(a, b) ((a >> b) | (a << (32 - b))) +#endif + +#if defined(_MSC_VER) && defined(_M_X64) +#define _VECTOR __vectorcall +#include +//#include //SSE2 +//#include //SSE3 +//#include //SSSE3 +//#include //SSE4.1 +//#include //SSE4.2 +//#include //SSE4A +//#include //AES +//#include //AVX +#define OPT_COMPATIBLE +#elif defined(__GNUC__) && defined(__x86_64__) +#include +#define _VECTOR +#endif + +#ifdef OPT_COMPATIBLE +static void _VECTOR xor_salsa8(__m128i B[4], const __m128i Bx[4], int i) +{ + __m128i X0, X1, X2, X3; + + if (i <= 128) { + // a xor 0 = a + X0 = B[0] = Bx[0]; + X1 = B[1] = Bx[1]; + X2 = B[2] = Bx[2]; + X3 = B[3] = Bx[3]; + } else { + X0 = B[0] = _mm_xor_si128(B[0], Bx[0]); + X1 = B[1] = _mm_xor_si128(B[1], Bx[1]); + X2 = B[2] = _mm_xor_si128(B[2], Bx[2]); + X3 = B[3] = _mm_xor_si128(B[3], Bx[3]); + } + + for (i = 0; i < 4; i++) { + /* Operate on columns. */ + X1.m128i_u32[0] ^= ROTL(X0.m128i_u32[0] + X3.m128i_u32[0], 7); + X2.m128i_u32[1] ^= ROTL(X1.m128i_u32[1] + X0.m128i_u32[1], 7); + X3.m128i_u32[2] ^= ROTL(X2.m128i_u32[2] + X1.m128i_u32[2], 7); + X0.m128i_u32[3] ^= ROTL(X3.m128i_u32[3] + X2.m128i_u32[3], 7); + + X2.m128i_u32[0] ^= ROTL(X1.m128i_u32[0] + X0.m128i_u32[0], 9); + X3.m128i_u32[1] ^= ROTL(X2.m128i_u32[1] + X1.m128i_u32[1], 9); + X0.m128i_u32[2] ^= ROTL(X3.m128i_u32[2] + X2.m128i_u32[2], 9); + X1.m128i_u32[3] ^= ROTL(X0.m128i_u32[3] + X3.m128i_u32[3], 9); + + X3.m128i_u32[0] ^= ROTL(X2.m128i_u32[0] + X1.m128i_u32[0], 13); + X0.m128i_u32[1] ^= ROTL(X3.m128i_u32[1] + X2.m128i_u32[1], 13); + X1.m128i_u32[2] ^= ROTL(X0.m128i_u32[2] + X3.m128i_u32[2], 13); + X2.m128i_u32[3] ^= ROTL(X1.m128i_u32[3] + X0.m128i_u32[3], 13); + + X0.m128i_u32[0] ^= ROTL(X3.m128i_u32[0] + X2.m128i_u32[0], 18); + X1.m128i_u32[1] ^= ROTL(X0.m128i_u32[1] + X3.m128i_u32[1], 18); + X2.m128i_u32[2] ^= ROTL(X1.m128i_u32[2] + X0.m128i_u32[2], 18); + X3.m128i_u32[3] ^= ROTL(X2.m128i_u32[3] + X1.m128i_u32[3], 18); + + /* Operate on rows. */ + X0.m128i_u32[1] ^= ROTL(X0.m128i_u32[0] + X0.m128i_u32[3], 7); X1.m128i_u32[2] ^= ROTL(X1.m128i_u32[1] + X1.m128i_u32[0], 7); + X2.m128i_u32[3] ^= ROTL(X2.m128i_u32[2] + X2.m128i_u32[1], 7); X3.m128i_u32[0] ^= ROTL(X3.m128i_u32[3] + X3.m128i_u32[2], 7); + X0.m128i_u32[2] ^= ROTL(X0.m128i_u32[1] + X0.m128i_u32[0], 9); X1.m128i_u32[3] ^= ROTL(X1.m128i_u32[2] + X1.m128i_u32[1], 9); + X2.m128i_u32[0] ^= ROTL(X2.m128i_u32[3] + X2.m128i_u32[2], 9); X3.m128i_u32[1] ^= ROTL(X3.m128i_u32[0] + X3.m128i_u32[3], 9); + + X0.m128i_u32[3] ^= ROTL(X0.m128i_u32[2] + X0.m128i_u32[1], 13); X1.m128i_u32[0] ^= ROTL(X1.m128i_u32[3] + X1.m128i_u32[2], 13); + X2.m128i_u32[1] ^= ROTL(X2.m128i_u32[0] + X2.m128i_u32[3], 13); X3.m128i_u32[2] ^= ROTL(X3.m128i_u32[1] + X3.m128i_u32[0], 13); + X0.m128i_u32[0] ^= ROTL(X0.m128i_u32[3] + X0.m128i_u32[2], 18); X1.m128i_u32[1] ^= ROTL(X1.m128i_u32[0] + X1.m128i_u32[3], 18); + X2.m128i_u32[2] ^= ROTL(X2.m128i_u32[1] + X2.m128i_u32[0], 18); X3.m128i_u32[3] ^= ROTL(X3.m128i_u32[2] + X3.m128i_u32[1], 18); + } + + B[0] = _mm_add_epi32(B[0], X0); + B[1] = _mm_add_epi32(B[1], X1); + B[2] = _mm_add_epi32(B[2], X2); + B[3] = _mm_add_epi32(B[3], X3); +} + +#else + +static inline void xor_salsa8(uint32_t B[16], const uint32_t Bx[16], int i) +{ + uint32_t x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15; + + if (i <= 128) { + // a xor 0 = a + x00 = B[ 0] = Bx[ 0]; x01 = B[ 1] = Bx[ 1]; x02 = B[ 2] = Bx[ 2]; x03 = B[ 3] = Bx[ 3]; + x04 = B[ 4] = Bx[ 4]; x05 = B[ 5] = Bx[ 5]; x06 = B[ 6] = Bx[ 6]; x07 = B[ 7] = Bx[ 7]; + x08 = B[ 8] = Bx[ 8]; x09 = B[ 9] = Bx[ 9]; x10 = B[10] = Bx[10]; x11 = B[11] = Bx[11]; + x12 = B[12] = Bx[12]; x13 = B[13] = Bx[13]; x14 = B[14] = Bx[14]; x15 = B[15] = Bx[15]; + } else { + x00 = (B[ 0] ^= Bx[ 0]); + x01 = (B[ 1] ^= Bx[ 1]); + x02 = (B[ 2] ^= Bx[ 2]); + x03 = (B[ 3] ^= Bx[ 3]); + x04 = (B[ 4] ^= Bx[ 4]); + x05 = (B[ 5] ^= Bx[ 5]); + x06 = (B[ 6] ^= Bx[ 6]); + x07 = (B[ 7] ^= Bx[ 7]); + x08 = (B[ 8] ^= Bx[ 8]); + x09 = (B[ 9] ^= Bx[ 9]); + x10 = (B[10] ^= Bx[10]); + x11 = (B[11] ^= Bx[11]); + x12 = (B[12] ^= Bx[12]); + x13 = (B[13] ^= Bx[13]); + x14 = (B[14] ^= Bx[14]); + x15 = (B[15] ^= Bx[15]); + } + + for (i = 0; i < 8; i += 2) { + /* Operate on columns. */ + x04 ^= ROTL(x00 + x12, 7); x09 ^= ROTL(x05 + x01, 7); + x14 ^= ROTL(x10 + x06, 7); x03 ^= ROTL(x15 + x11, 7); + + x08 ^= ROTL(x04 + x00, 9); x13 ^= ROTL(x09 + x05, 9); + x02 ^= ROTL(x14 + x10, 9); x07 ^= ROTL(x03 + x15, 9); + + x12 ^= ROTL(x08 + x04, 13); x01 ^= ROTL(x13 + x09, 13); + x06 ^= ROTL(x02 + x14, 13); x11 ^= ROTL(x07 + x03, 13); + + x00 ^= ROTL(x12 + x08, 18); x05 ^= ROTL(x01 + x13, 18); + x10 ^= ROTL(x06 + x02, 18); x15 ^= ROTL(x11 + x07, 18); + + /* Operate on rows. */ + x01 ^= ROTL(x00 + x03, 7); x06 ^= ROTL(x05 + x04, 7); + x11 ^= ROTL(x10 + x09, 7); x12 ^= ROTL(x15 + x14, 7); + + x02 ^= ROTL(x01 + x00, 9); x07 ^= ROTL(x06 + x05, 9); + x08 ^= ROTL(x11 + x10, 9); x13 ^= ROTL(x12 + x15, 9); + + x03 ^= ROTL(x02 + x01, 13); x04 ^= ROTL(x07 + x06, 13); + x09 ^= ROTL(x08 + x11, 13); x14 ^= ROTL(x13 + x12, 13); + + x00 ^= ROTL(x03 + x02, 18); x05 ^= ROTL(x04 + x07, 18); + x10 ^= ROTL(x09 + x08, 18); x15 ^= ROTL(x14 + x13, 18); + } + B[ 0] += x00; + B[ 1] += x01; + B[ 2] += x02; + B[ 3] += x03; + B[ 4] += x04; + B[ 5] += x05; + B[ 6] += x06; + B[ 7] += x07; + B[ 8] += x08; + B[ 9] += x09; + B[10] += x10; + B[11] += x11; + B[12] += x12; + B[13] += x13; + B[14] += x14; + B[15] += x15; +} + +#endif + +static const uint32_t sha256_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ (x >> 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ (x >> 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + do { \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; \ + } while (0) + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + sha256_k[i]) + + +static void sha256_transform_volatile(uint32_t *state, uint32_t *block) +{ + uint32_t* W=block; //note: block needs to be a mutable 64 int32_t + uint32_t S[8]; + uint32_t t0, t1; + int i; + + for (i = 16; i < 64; i += 2) { + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + W[i+1] = s1(W[i - 1]) + W[i - 6] + s0(W[i - 14]) + W[i - 15]; + } + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0); + RNDr(S, W, 1); + RNDr(S, W, 2); + RNDr(S, W, 3); + RNDr(S, W, 4); + RNDr(S, W, 5); + RNDr(S, W, 6); + RNDr(S, W, 7); + RNDr(S, W, 8); + RNDr(S, W, 9); + RNDr(S, W, 10); + RNDr(S, W, 11); + RNDr(S, W, 12); + RNDr(S, W, 13); + RNDr(S, W, 14); + RNDr(S, W, 15); + RNDr(S, W, 16); + RNDr(S, W, 17); + RNDr(S, W, 18); + RNDr(S, W, 19); + RNDr(S, W, 20); + RNDr(S, W, 21); + RNDr(S, W, 22); + RNDr(S, W, 23); + RNDr(S, W, 24); + RNDr(S, W, 25); + RNDr(S, W, 26); + RNDr(S, W, 27); + RNDr(S, W, 28); + RNDr(S, W, 29); + RNDr(S, W, 30); + RNDr(S, W, 31); + RNDr(S, W, 32); + RNDr(S, W, 33); + RNDr(S, W, 34); + RNDr(S, W, 35); + RNDr(S, W, 36); + RNDr(S, W, 37); + RNDr(S, W, 38); + RNDr(S, W, 39); + RNDr(S, W, 40); + RNDr(S, W, 41); + RNDr(S, W, 42); + RNDr(S, W, 43); + RNDr(S, W, 44); + RNDr(S, W, 45); + RNDr(S, W, 46); + RNDr(S, W, 47); + RNDr(S, W, 48); + RNDr(S, W, 49); + RNDr(S, W, 50); + RNDr(S, W, 51); + RNDr(S, W, 52); + RNDr(S, W, 53); + RNDr(S, W, 54); + RNDr(S, W, 55); + RNDr(S, W, 56); + RNDr(S, W, 57); + RNDr(S, W, 58); + RNDr(S, W, 59); + RNDr(S, W, 60); + RNDr(S, W, 61); + RNDr(S, W, 62); + RNDr(S, W, 63); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; +} + +// standard sha256 hash +#if 1 +static void sha256_hash(unsigned char *hash, const unsigned char *data, int len) +{ + uint32_t _ALIGN(64) S[16]; + uint32_t _ALIGN(64) T[64]; + int i, r; + + sha256_init(S); + for (r = len; r > -9; r -= 64) { + if (r < 64) + memset(T, 0, 64); + memcpy(T, data + len - r, r > 64 ? 64 : (r < 0 ? 0 : r)); + if (r >= 0 && r < 64) + ((unsigned char *)T)[r] = 0x80; + for (i = 0; i < 16; i++) + T[i] = be32dec(T + i); + if (r < 56) + T[15] = 8 * len; + //sha256_transform(S, T, 0); + sha256_transform_volatile(S, T); + } + for (i = 0; i < 8; i++) + be32enc((uint32_t *)hash + i, S[i]); +} +#else +#include +static void sha256_hash(unsigned char *hash, const unsigned char *data, int len) +{ + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, data, len); + SHA256_Final(hash, &ctx); +} +#endif + +// hash exactly 64 bytes (ie, sha256 block size) +static void sha256_hash512(uint32_t *hash, const uint32_t *data) +{ + uint32_t _ALIGN(64) S[16]; + uint32_t _ALIGN(64) T[64]; + uchar _ALIGN(64) E[64*4] = { 0 }; + int i; + + sha256_init(S); + + for (i = 0; i < 16; i++) + T[i] = be32dec(&data[i]); + sha256_transform_volatile(S, T); + + E[3] = 0x80; + E[61] = 0x02; // T[15] = 8 * 64 => 0x200; + sha256_transform_volatile(S, (uint32_t*)E); + + for (i = 0; i < 8; i++) + be32enc(&hash[i], S[i]); +} + +void pluck_hash(uint32_t *hash, const uint32_t *data, uchar *hashbuffer, const int N) +{ + int size = N * 1024; + sha256_hash(hashbuffer, (void*)data, BLOCK_HEADER_SIZE); + memset(&hashbuffer[32], 0, 32); + + for(int i = 64; i < size - 32; i += 32) + { + uint32_t _ALIGN(64) randseed[16]; + uint32_t _ALIGN(64) randbuffer[16]; + uint32_t _ALIGN(64) joint[16]; + //i-4 because we use integers for all references against this, and we don't want to go 3 bytes over the defined area + //we could use size here, but then it's probable to use 0 as the value in most cases + int randmax = i - 4; + + //setup randbuffer to be an array of random indexes + memcpy(randseed, &hashbuffer[i - 64], 64); + + if(i > 128) memcpy(randbuffer, &hashbuffer[i - 128], 64); + //else memset(randbuffer, 0, 64); + + xor_salsa8((void*)randbuffer, (void*)randseed, i); + memcpy(joint, &hashbuffer[i - 32], 32); + + //use the last hash value as the seed + for (int j = 32; j < 64; j += 4) + { + //every other time, change to next random index + //randmax - 32 as otherwise we go beyond memory that's already been written to + uint32_t rand = randbuffer[(j - 32) >> 2] % (randmax - 32); + joint[j >> 2] = *((uint32_t *)&hashbuffer[rand]); + } + + sha256_hash512((uint32_t*) &hashbuffer[i], joint); + + //setup randbuffer to be an array of random indexes + //use last hash value and previous hash value(post-mixing) + memcpy(randseed, &hashbuffer[i - 32], 64); + + if(i > 128) memcpy(randbuffer, &hashbuffer[i - 128], 64); + //else memset(randbuffer, 0, 64); + + xor_salsa8((void*)randbuffer, (void*)randseed, i); + + //use the last hash value as the seed + for (int j = 0; j < 32; j += 2) + { + uint32_t rand = randbuffer[j >> 1] % randmax; + *((uint32_t *)(hashbuffer + rand)) = *((uint32_t *)(hashbuffer + j + randmax)); + } + } + + memcpy(hash, hashbuffer, 32); +} + +int scanhash_pluck(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, + unsigned char *scratchbuf, int N) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + uint32_t n = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0xffff; + + for (int k = 0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + const uint32_t Htarg = ptarget[7]; + do { + //be32enc(&endiandata[19], n); + endiandata[19] = n; + pluck_hash(hash, endiandata, scratchbuf, N); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) + { + work_set_target_ratio(work, hash); + *hashes_done = n - first_nonce + 1; + pdata[19] = htobe32(endiandata[19]); + return 1; + } + n++; + } while (n < max_nonce && !(*restart)); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/quark.c b/algo/quark.c new file mode 100644 index 000000000..d8b0869b3 --- /dev/null +++ b/algo/quark.c @@ -0,0 +1,135 @@ +#include "miner.h" + +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" + +/* Move init out of loop, so init once externally, + and then use one single memcpy with that bigger memory block */ +typedef struct { + sph_blake512_context blake1, blake2; + sph_bmw512_context bmw1, bmw2; + sph_groestl512_context groestl1, groestl2; + sph_skein512_context skein1, skein2; + sph_jh512_context jh1, jh2; + sph_keccak512_context keccak1, keccak2; + bool init_done; +} quarkhash_context_holder; + +static quarkhash_context_holder _ALIGN(128) cached_ctx; + +void init_quarkhash_contexts() +{ + sph_blake512_init(&cached_ctx.blake1); + sph_bmw512_init(&cached_ctx.bmw1); + sph_groestl512_init(&cached_ctx.groestl1); + sph_skein512_init(&cached_ctx.skein1); + sph_groestl512_init(&cached_ctx.groestl2); + sph_jh512_init(&cached_ctx.jh1); + sph_blake512_init(&cached_ctx.blake2); + sph_bmw512_init(&cached_ctx.bmw2); + sph_keccak512_init(&cached_ctx.keccak1); + sph_skein512_init(&cached_ctx.skein2); + sph_keccak512_init(&cached_ctx.keccak2); + sph_jh512_init(&cached_ctx.jh2); + cached_ctx.init_done = true; +} + +void quarkhash(void *state, const void *input) +{ + uint32_t _ALIGN(128) hash[16]; + quarkhash_context_holder _ALIGN(128) ctx; + uint32_t mask = 8; + + if (cached_ctx.init_done) + memcpy(&ctx, &cached_ctx, sizeof(cached_ctx)); + else { + applog(LOG_ERR, "Attempt to hash quark without init!"); + exit(1); + } + + sph_blake512 (&ctx.blake1, input, 80); + sph_blake512_close (&ctx.blake1, hash); //0 + + sph_bmw512 (&ctx.bmw1, hash, 64); + sph_bmw512_close(&ctx.bmw1, hash); //1 + + if (hash[0] & mask) { + sph_groestl512 (&ctx.groestl1, hash, 64); + sph_groestl512_close(&ctx.groestl1, hash); //2 + } else { + sph_skein512 (&ctx.skein1, hash, 64); + sph_skein512_close(&ctx.skein1, hash); //2 + } + + sph_groestl512 (&ctx.groestl2, hash, 64); + sph_groestl512_close(&ctx.groestl2, hash); //3 + + sph_jh512 (&ctx.jh1, hash, 64); + sph_jh512_close(&ctx.jh1, hash); //4 + + if (hash[0] & mask) { + sph_blake512 (&ctx.blake2, hash, 64); + sph_blake512_close(&ctx.blake2, hash); //5 + } else { + sph_bmw512 (&ctx.bmw2, hash, 64); + sph_bmw512_close(&ctx.bmw2, hash); //5 + } + + sph_keccak512 (&ctx.keccak1, hash, 64); + sph_keccak512_close(&ctx.keccak1, hash); //6 + + sph_skein512 (&ctx.skein2, hash, 64); + sph_skein512_close(&ctx.skein2, hash); //7 + + if (hash[0] & mask) { + sph_keccak512 (&ctx.keccak2, hash, 64); + sph_keccak512_close(&ctx.keccak2, hash); //8 + } else { + sph_jh512 (&ctx.jh2, hash, 64); + sph_jh512_close(&ctx.jh2, hash); //8 + } + + memcpy(state, hash, 32); +} + +int scanhash_quark(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + quarkhash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/qubit.c b/algo/qubit.c new file mode 100644 index 000000000..c79b377c2 --- /dev/null +++ b/algo/qubit.c @@ -0,0 +1,116 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_luffa.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" + +void qubithash(void *output, const void *input) +{ + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + + uint8_t hash[64]; + + sph_luffa512_init(&ctx_luffa); + sph_luffa512 (&ctx_luffa, input, 80); + sph_luffa512_close(&ctx_luffa, (void*) hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512 (&ctx_cubehash, (const void*) hash, 64); + sph_cubehash512_close(&ctx_cubehash, (void*) hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512 (&ctx_shavite, (const void*) hash, 64); + sph_shavite512_close(&ctx_shavite, (void*) hash); + + sph_simd512_init(&ctx_simd); + sph_simd512 (&ctx_simd, (const void*) hash, 64); + sph_simd512_close(&ctx_simd, (void*) hash); + + sph_echo512_init(&ctx_echo); + sph_echo512 (&ctx_echo, (const void*) hash, 64); + sph_echo512_close(&ctx_echo, (void*) hash); + + memcpy(output, hash, 32); +} + +int scanhash_qubit(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + uint32_t n = pdata[19] - 1; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + qubithash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/rainforest.c b/algo/rainforest.c new file mode 100644 index 000000000..d938fda4a --- /dev/null +++ b/algo/rainforest.c @@ -0,0 +1,893 @@ +// RainForest hash algorithm +// Author: Bill Schneider +// Date: Feb 13th, 2018 +// +// RainForest uses native integer operations which are extremely fast on +// modern 64-bit processors, significantly slower on 32-bit processors such +// as GPUs, and extremely slow if at all implementable on FPGAs and ASICs. +// It makes an intensive use of the L1 cache to maintain a heavy intermediary +// state favoring modern CPUs compared to GPUs (small L1 cache shared by many +// shaders) or FPGAs (very hard to implement the required low-latency cache) +// when scanning ranges for nonces. The purpose is to create a fair balance +// between all mining equipments, from mobile phones to extreme performance +// GPUs and to rule out farming factories relying on ASICs and FPGAs. The +// CRC32 instruction is used a lot as it is extremely fast on low-power ARM +// chips and allows such devices to rival high-end PCs mining performance. +// +// Tests on various devices have shown the following performance : +// +--------------------------------------------------------------------------+ +// | CPU/GPU Clock Threads Full hash Nonce scan Watts Cost | +// | (MHz) (80 bytes) (4 bytes) total | +// | Core i7-6700k 4000 8 390 kH/s 1642 kH/s 200 ~$350+PC | +// | Radeon RX560 1300 1024 1100 kH/s 1650 kH/s 300 ~$180+PC | +// | RK3368 (8*A53) 1416 8 534 kH/s 1582 kH/s 6 $60 (Geekbox) | +// +--------------------------------------------------------------------------+ +// +// Build instructions on Ubuntu 16.04 : +// - on x86: use gcc -march=native or -maes to enable AES-NI +// - on ARMv8: use gcc -march=native or -march=armv8-a+crypto+crc to enable +// CRC32 and AES extensions. +// +// Note: always use the same options to build all files! + +#include + +#include +#include +#include +#include + +//#define DEBUG_ALGO + +/* Rijndael's substitution box for sub_bytes step */ +static uint8_t SBOX[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +/*--- The parts below are not used when crypto extensions are available ---*/ +/* Use -march=armv8-a+crypto on ARMv8 to use crypto extensions */ +/* Use -maes on x86_64 to use AES-NI */ +#if defined(RF_NOASM) || (!defined(__aarch64__) || !defined(__ARM_FEATURE_CRYPTO)) && (!defined(__x86_64__) || !defined(__AES__)) + +/* shifts to do for shift_rows step */ +static uint8_t shifts[16] = { + 0, 5, 10, 15, + 4, 9, 14, 3, + 8, 13, 2, 7, + 12, 1, 6, 11 +}; + +/* add the round key to the state with simple XOR operation */ +static void add_round_key(uint8_t * state, uint8_t * rkey) { + uint8_t i; + for (i = 0; i < 16; i++) + state[i] ^= rkey[i]; +} + +/* substitute all bytes using Rijndael's substitution box */ +static void sub_bytes(uint8_t * state) { + uint8_t i; + for (i = 0; i < 16; i++) + state[i] = SBOX[state[i]]; +} + +/* imagine the state not as 1-dimensional, but a 4x4 grid; + * this step shifts the rows of this grid around */ +static void shift_rows(uint8_t * state) { + uint8_t temp[16]; + uint8_t i; + + for (i = 0; i < 16; i++) { + temp[i] = state[shifts[i]]; + } + + for (i = 0; i < 16; i++) { + state[i] = temp[i]; + } +} + +/* mix columns */ +static void mix_columns(uint8_t * state) { + uint8_t a[4]; + uint8_t b[4]; + uint8_t h, i, k; + + for (k = 0; k < 4; k++) { + for (i = 0; i < 4; i++) { + a[i] = state[i + 4 * k]; + h = state[i + 4 * k] & 0x80; /* hi bit */ + b[i] = state[i + 4 * k] << 1; + + if (h == 0x80) { + b[i] ^= 0x1b; /* Rijndael's Galois field */ + } + } + + state[4 * k] = b[0] ^ a[3] ^ a[2] ^ b[1] ^ a[1]; + state[1 + 4 * k] = b[1] ^ a[0] ^ a[3] ^ b[2] ^ a[2]; + state[2 + 4 * k] = b[2] ^ a[1] ^ a[0] ^ b[3] ^ a[3]; + state[3 + 4 * k] = b[3] ^ a[2] ^ a[1] ^ b[0] ^ a[0]; + } +} +#endif // (!defined(__aarch64__) || !defined(__ARM_FEATURE_CRYPTO)) && (!defined(__x86_64__) || !defined(__AES__)) + + +/* key schedule stuff */ + +/* simple function to rotate 4 byte array */ +static inline uint32_t rotate32(uint32_t in) { +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + in = (in >> 8) | (in << 24); +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + in = (in << 8) | (in >> 24); +#else + uint8_t *b = (uint8_t *)&in, temp = b[0]; + b[0] = b[1]; b[1] = b[2]; b[2] = b[3]; b[3] = temp; +#endif + return in; +} + +/* key schedule core operation */ +static inline uint32_t sbox(uint32_t in, uint8_t n) { + in = (SBOX[in & 255]) | (SBOX[(in >> 8) & 255] << 8) | (SBOX[(in >> 16) & 255] << 16) | (SBOX[(in >> 24) & 255] << 24); +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + in ^= n; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + in ^= n << 24; +#else + *(uint8_t *)&in ^= n; +#endif + return in; +} + +// this version is optimized for exactly two rounds. +// _state_ must be 16-byte aligned. +static void aes2r_encrypt(uint8_t * state, uint8_t * key) { + uint32_t _ALIGN(16) key_schedule[12]; + uint32_t t; + + /* initialize key schedule; its first 16 bytes are the key */ + key_schedule[0] = ((uint32_t *)key)[0]; + key_schedule[1] = ((uint32_t *)key)[1]; + key_schedule[2] = ((uint32_t *)key)[2]; + key_schedule[3] = ((uint32_t *)key)[3]; + t = key_schedule[3]; + + t = rotate32(t); + t = sbox(t, 1); + t = key_schedule[4] = key_schedule[0] ^ t; + t = key_schedule[5] = key_schedule[1] ^ t; + t = key_schedule[6] = key_schedule[2] ^ t; + t = key_schedule[7] = key_schedule[3] ^ t; + + t = rotate32(t); + t = sbox(t, 2); + t = key_schedule[8] = key_schedule[4] ^ t; + t = key_schedule[9] = key_schedule[5] ^ t; + t = key_schedule[10] = key_schedule[6] ^ t; + t = key_schedule[11] = key_schedule[7] ^ t; + +// Use -march=armv8-a+crypto+crc to get this one +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRYPTO) + asm volatile( + "ld1 {v0.16b},[%0] \n" + "ld1 {v1.16b,v2.16b,v3.16b},[%1] \n" + "aese v0.16b,v1.16b \n" // round1: add_round_key,sub_bytes,shift_rows + "aesmc v0.16b,v0.16b \n" // round1: mix_columns + "aese v0.16b,v2.16b \n" // round2: add_round_key,sub_bytes,shift_rows + "eor v0.16b,v0.16b,v3.16b \n" // finish: add_round_key + "st1 {v0.16b},[%0] \n" + : /* only output is in *state */ + : "r"(state), "r"(key_schedule) + : "v0", "v1", "v2", "v3", "cc", "memory"); + +// Use -maes to get this one +#elif defined(__x86_64__) && defined(__AES__) + asm volatile( + "movups (%0), %%xmm0 \n" + "movups (%1), %%xmm1 \n" + "pxor %%xmm1,%%xmm0 \n" // add_round_key(state, key_schedule) + "movups 16(%1),%%xmm2 \n" + "movups 32(%1),%%xmm1 \n" + "aesenc %%xmm2,%%xmm0 \n" // first round + "aesenclast %%xmm1,%%xmm0 \n" // final round + "movups %%xmm0, (%0) \n" + : /* only output is in *state */ + : "r"(state), "r" (key_schedule) + : "xmm0", "xmm1", "xmm2", "cc", "memory"); + +#else + /* first round of the algorithm */ + add_round_key(state, (void*)&key_schedule[0]); + sub_bytes(state); + shift_rows(state); + mix_columns(state); + add_round_key(state, (void*)&key_schedule[4]); + + /* final round of the algorithm */ + sub_bytes(state); + shift_rows(state); + add_round_key(state, (void*)&key_schedule[8]); + +#endif +} + +// this seems necessary only for gcc, otherwise hash is bogus +#ifdef _MSC_VER +typedef unsigned long ulong; +typedef uint8_t rf_u8; +typedef uint16_t rf_u16; +typedef uint32_t rf_u32; +typedef uint64_t rf_u64; +#else +typedef __attribute__((may_alias)) uint8_t rf_u8; +typedef __attribute__((may_alias)) uint16_t rf_u16; +typedef __attribute__((may_alias)) uint32_t rf_u32; +typedef __attribute__((may_alias)) uint64_t rf_u64; +#endif + +// 2048 entries for the rambox => 16kB +#define RAMBOX_SIZE 2048 +#define RAMBOX_LOOPS 4 +#define RAMBOX_HIST 32 + +typedef union { + rf_u8 b[32]; + rf_u16 w[16]; + rf_u32 d[8]; + rf_u64 q[4]; +} hash256_t; + +typedef struct _ALIGN(128) rf_ctx { + uint32_t word; // LE pending message + uint32_t len; // total message length + uint32_t crc; + uint32_t changes; // must remain lower than RAMBOX_HIST + hash256_t _ALIGN(32) hash; + uint16_t hist[RAMBOX_HIST]; + uint64_t _ALIGN(64) rambox[RAMBOX_SIZE]; +} rf256_ctx_t; + +// these archs are fine with unaligned reads +#if defined(__x86_64__)||defined(__aarch64__) +#define RF_UNALIGNED_LE64 +#define RF_UNALIGNED_LE32 +#elif defined(__i386__)||defined(__ARM_ARCH_7A__) +#define RF_UNALIGNED_LE32 +#endif + +#define RF256_INIT_CRC 20180213 + +// the table is used as an 8 bit-aligned array of uint64_t for the first word, +// and as a 16 bit-aligned array of uint64_t for the second word. It is filled +// with the sha256 of "RainForestProCpuAntiAsic", iterated over and over until +// the table is filled. The highest offset being ((uint16_t *)table)[255] we +// need to add 6 extra bytes at the end to read an uint64_t. Maybe calculated +// on a UNIX system with this loop : +// +// ref="RainForestProCpuAntiAsic" +// for ((i=0;i<18;i++)); do +// set $(echo -n $ref|sha256sum) +// echo $1|sed 's/\(..\)/0x\1,/g' +// ref=$(printf $(echo $1|sed 's/\(..\)/\\x\1/g')) +// done + +const uint8_t rf_table[256*2+6] = { + 0x8e,0xc1,0xa8,0x04,0x38,0x78,0x7c,0x54,0x29,0x23,0x1b,0x78,0x9f,0xf9,0x27,0x54, + 0x11,0x78,0x95,0xb6,0xaf,0x78,0x45,0x16,0x2b,0x9e,0x91,0xe8,0x97,0x25,0xf8,0x63, + 0x82,0x56,0xcf,0x48,0x6f,0x82,0x14,0x0d,0x61,0xbe,0x47,0xd1,0x37,0xee,0x30,0xa9, + 0x28,0x1e,0x4b,0xbf,0x07,0xcd,0x41,0xdf,0x23,0x21,0x12,0xb8,0x81,0x99,0x1d,0xe6, + 0x68,0xcf,0xfa,0x2d,0x8e,0xb9,0x88,0xa7,0x15,0xce,0x9e,0x2f,0xeb,0x1b,0x0f,0x67, + 0x20,0x68,0x6c,0xa9,0x5d,0xc1,0x7c,0x76,0xdf,0xbd,0x98,0x61,0xb4,0x14,0x65,0x40, + 0x1e,0x72,0x51,0x74,0x93,0xd3,0xad,0xbe,0x46,0x0a,0x25,0xfb,0x6a,0x5e,0x1e,0x8a, + 0x5a,0x03,0x3c,0xab,0x12,0xc2,0xd4,0x07,0x91,0xab,0xc9,0xdf,0x92,0x2c,0x85,0x6a, + 0xa6,0x25,0x1e,0x66,0x50,0x26,0x4e,0xa8,0xbd,0xda,0x88,0x1b,0x95,0xd4,0x00,0xeb, + 0x0d,0x1c,0x9b,0x3c,0x86,0xc7,0xb2,0xdf,0xb4,0x5a,0x36,0x15,0x8e,0x04,0xd2,0x54, + 0x79,0xd2,0x3e,0x3d,0x99,0x50,0xa6,0x12,0x4c,0x32,0xc8,0x51,0x14,0x4d,0x4b,0x0e, + 0xbb,0x17,0x80,0x8f,0xa4,0xc4,0x99,0x72,0xd7,0x14,0x4b,0xef,0xed,0x14,0xe9,0x17, + 0xfa,0x9b,0x5d,0x37,0xd6,0x2f,0xef,0x02,0xd6,0x71,0x0a,0xbd,0xc5,0x40,0x11,0x90, + 0x90,0x4e,0xb4,0x4c,0x72,0x51,0x7a,0xd8,0xba,0x30,0x4d,0x8c,0xe2,0x11,0xbb,0x6d, + 0x4b,0xbc,0x6f,0x14,0x0c,0x9f,0xfa,0x5e,0x66,0x40,0x45,0xcb,0x7d,0x1b,0x3a,0xc5, + 0x5e,0x9c,0x1e,0xcc,0xbd,0x16,0x3b,0xcf,0xfb,0x2a,0xd2,0x08,0x2a,0xf8,0x3d,0x46, + 0x93,0x90,0xb3,0x66,0x81,0x34,0x7f,0x6d,0x9b,0x8c,0x99,0x03,0xc5,0x27,0xa3,0xd9, + 0xce,0x90,0x88,0x0f,0x55,0xc3,0xa1,0x60,0x53,0xc8,0x0d,0x25,0xae,0x61,0xd9,0x72, + 0x48,0x1d,0x6c,0x61,0xd2,0x87,0xdd,0x3d,0x23,0xf5,0xde,0x93,0x39,0x4c,0x43,0x9a, + 0xf9,0x37,0xf2,0x61,0xd7,0xf8,0xea,0x65,0xf0,0xf1,0xde,0x3f,0x05,0x57,0x83,0x81, + 0xde,0x02,0x62,0x49,0xd4,0x32,0x7e,0x4a,0xd4,0x9f,0x40,0x7e,0xb9,0x91,0xb1,0x35, + 0xf7,0x62,0x3f,0x65,0x9e,0x4d,0x2b,0x10,0xde,0xd4,0x77,0x64,0x0f,0x84,0xad,0x92, + 0xe7,0xa3,0x8a,0x10,0xc1,0x14,0xeb,0x57,0xc4,0xad,0x8e,0xc2,0xc7,0x32,0xa3,0x7e, + 0x50,0x1f,0x7c,0xbb,0x2e,0x5f,0xf5,0x18,0x22,0xea,0xec,0x9d,0xa4,0x77,0xcd,0x85, + 0x04,0x2f,0x20,0x61,0x72,0xa7,0x0c,0x92,0x06,0x4d,0x01,0x70,0x9b,0x35,0xa1,0x27, + 0x32,0x6e,0xb9,0x78,0xe0,0xaa,0x5f,0x91,0xa6,0x51,0xe3,0x63,0xf8,0x97,0x2f,0x60, + 0xd9,0xfb,0x15,0xe5,0x59,0xcf,0x31,0x3c,0x61,0xc7,0xb5,0x61,0x2a,0x6b,0xdd,0xd1, + 0x09,0x70,0xc0,0xcf,0x94,0x7a,0xcc,0x31,0x94,0xb1,0xa2,0xf6,0x95,0xc0,0x38,0x3d, + 0xef,0x19,0x30,0x70,0xdd,0x62,0x32,0x8f,0x7c,0x30,0xb9,0x18,0xf8,0xe7,0x8f,0x0a, + 0xaa,0xb6,0x00,0x86,0xf2,0xe0,0x30,0x5f,0xa2,0xe8,0x00,0x8e,0x05,0xa0,0x22,0x18, + 0x9f,0x83,0xd4,0x3a,0x85,0x10,0xb9,0x51,0x8d,0x07,0xf0,0xb3,0xcd,0x9b,0x55,0xa1, + 0x14,0xce,0x0f,0xb2,0xcf,0xb8,0xce,0x2d,0xe6,0xe8,0x35,0x32,0x1f,0x22,0xb5,0xec, + 0xd0,0xb9,0x72,0xa8,0xb4,0x97 + //,0x6e,0x0a,0x47,0xcd,0x5a,0xf0,0xdc,0xeb,0xfd,0x46, + //0xe5,0x6e,0x83,0xe6,0x1a,0xcc,0x4a,0x8b,0xa5,0x28,0x9e,0x50,0x48,0xa9,0xa2,0x6b, +}; + +// this is made of the last iteration of the rf_table (18th transformation) +const uint8_t rf256_iv[32] = { + 0x78,0xe9,0x90,0xd3,0xb3,0xc8,0x9b,0x7b,0x0a,0xc4,0x86,0x6e,0x4e,0x38,0xb3,0x6b, + 0x33,0x68,0x7c,0xed,0x73,0x35,0x4b,0x0a,0x97,0x25,0x4c,0x77,0x7a,0xaa,0x61,0x1b +}; + +// crc32 lookup tables +#if !defined(__aarch64__) || !defined(__ARM_FEATURE_CRC32) +const uint32_t rf_crc32_table[256] = { + /* 0x00 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + /* 0x04 */ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + /* 0x08 */ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + /* 0x0c */ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + /* 0x10 */ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + /* 0x14 */ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + /* 0x18 */ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + /* 0x1c */ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + /* 0x20 */ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + /* 0x24 */ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + /* 0x28 */ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + /* 0x2c */ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + /* 0x30 */ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + /* 0x34 */ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + /* 0x38 */ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + /* 0x3c */ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + /* 0x40 */ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + /* 0x44 */ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + /* 0x48 */ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + /* 0x4c */ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + /* 0x50 */ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + /* 0x54 */ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + /* 0x58 */ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + /* 0x5c */ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + /* 0x60 */ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + /* 0x64 */ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + /* 0x68 */ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + /* 0x6c */ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + /* 0x70 */ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + /* 0x74 */ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + /* 0x78 */ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + /* 0x7c */ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + /* 0x80 */ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + /* 0x84 */ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + /* 0x88 */ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + /* 0x8c */ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + /* 0x90 */ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + /* 0x94 */ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + /* 0x98 */ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + /* 0x9c */ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + /* 0xa0 */ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + /* 0xa4 */ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + /* 0xa8 */ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + /* 0xac */ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + /* 0xb0 */ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + /* 0xb4 */ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + /* 0xb8 */ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + /* 0xbc */ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + /* 0xc0 */ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + /* 0xc4 */ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + /* 0xc8 */ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + /* 0xcc */ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + /* 0xd0 */ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + /* 0xd4 */ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + /* 0xd8 */ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + /* 0xdc */ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + /* 0xe0 */ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + /* 0xe4 */ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + /* 0xe8 */ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + /* 0xec */ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + /* 0xf0 */ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + /* 0xf4 */ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + /* 0xf8 */ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + /* 0xfc */ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; +#endif + +// compute the crc32 of 32-bit message _msg_ from previous crc _crc_. +// build with -mcpu=cortex-a53+crc to enable native CRC instruction on ARM +static inline uint32_t rf_crc32_32(uint32_t crc, uint32_t msg) { +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + asm("crc32w %w0,%w0,%w1\n":"+r"(crc):"r"(msg)); +#else + crc=crc^msg; + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); +#endif + return crc; +} + +//static inline uint32_t rf_crc32_24(uint32_t crc, uint32_t msg) { +//#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) +// asm("crc32b %w0,%w0,%w1\n":"+r"(crc):"r"(msg)); +// asm("crc32h %w0,%w0,%w1\n":"+r"(crc):"r"(msg>>8)); +//#else +// crc=crc^msg; +// crc=rf_crc32_table[crc&0xff]^(crc>>8); +// crc=rf_crc32_table[crc&0xff]^(crc>>8); +// crc=rf_crc32_table[crc&0xff]^(crc>>8); +//#endif +// return crc; +//} +// +//static inline uint32_t rf_crc32_16(uint32_t crc, uint32_t msg) { +//#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) +// asm("crc32h %w0,%w0,%w1\n":"+r"(crc):"r"(msg)); +//#else +// crc=crc^msg; +// crc=rf_crc32_table[crc&0xff]^(crc>>8); +// crc=rf_crc32_table[crc&0xff]^(crc>>8); +//#endif +// return crc; +//} +// +//static inline uint32_t rf_crc32_8(uint32_t crc, uint32_t msg) { +//#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) +// asm("crc32b %w0,%w0,%w1\n":"+r"(crc):"r"(msg)); +//#else +// crc=crc^msg; +// crc=rf_crc32_table[crc&0xff]^(crc>>8); +//#endif +// return crc; +//} + +// add to _msg_ its own crc32. use -mcpu=cortex-a53+crc to enable native CRC +// instruction on ARM. +static inline uint64_t rf_add64_crc32(uint64_t msg) { + uint64_t crc=0; +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + asm("crc32x %w0,%w0,%x1\n":"+r"(crc):"r"(msg)); +#else + crc^=(uint32_t)msg; + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + + crc^=msg>>32; + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); + crc=rf_crc32_table[crc&0xff]^(crc>>8); +#endif + return msg+crc; +} + +// mix the current state with the crc and return the new crc +static inline uint32_t rf_crc32x4(rf_u32 *state, uint32_t crc) { + crc=state[0]=rf_crc32_32(crc, state[0]); + crc=state[1]=rf_crc32_32(crc, state[1]); + crc=state[2]=rf_crc32_32(crc, state[2]); + crc=state[3]=rf_crc32_32(crc, state[3]); + return crc; +} + +// read 64 bit from possibly unaligned memory address _p_ in little endian mode +static inline uint64_t rf_memr64(const uint8_t *p) { +#ifdef RF_UNALIGNED_LE64 + return *(uint64_t *)p; +#else + uint64_t ret; + int byte; + for (ret=byte=0; byte<8; byte++) + ret+=(uint64_t)p[byte]<<(byte*8); + return ret; +#endif +} + +// return rainforest lower word entry for index +static inline uint64_t rf_wltable(uint8_t index) { + return rf_memr64(&rf_table[index]); +} + +// return rainforest upper word entry for _index_ +static inline uint64_t rf_whtable(uint8_t index) { + return rf_memr64(&rf_table[index*2]); +} + +// rotate left vector _v_ by _bits_ bits +static inline uint64_t rf_rotl64(uint64_t v, uint8_t bits) { +#if !defined(__ARM_ARCH_8A) && !defined(__AARCH64EL__) && !defined(x86_64) + bits&=63; +#endif + return (v<>(64-bits)); +} + +// rotate right vector _v_ by _bits_ bits +static inline uint64_t rf_rotr64(uint64_t v, uint8_t bits) { +#if !defined(__ARM_ARCH_8A) && !defined(__AARCH64EL__) && !defined(x86_64) + bits&=63; +#endif + return (v>>bits)|(v<<(64-bits)); +} + +// reverse all bytes in the word _v_ +static inline uint64_t rf_bswap64(uint64_t v) { +#if defined(__x86_64__) && !defined(_MSC_VER) + asm("bswap %0":"+r"(v)); +#elif defined(__aarch64__) + asm("rev %0,%0\n":"+r"(v)); +#else + v=((v&0xff00ff00ff00ff00ULL)>>8)|((v&0x00ff00ff00ff00ffULL)<<8); + v=((v&0xffff0000ffff0000ULL)>>16)|((v&0x0000ffff0000ffffULL)<<16); + v=(v>>32)|(v<<32); +#endif + return v; +} + +// lookup _old_ in _rambox_, update it and perform a substitution if a matching +// value is found. +static inline uint32_t rf_rambox(rf256_ctx_t *ctx, uint64_t old) { + uint64_t *p, k; + uint32_t idx; + int loops; + + for (loops=0; loopschanges < RAMBOX_HIST) + ctx->hist[ctx->changes++] = idx; + p=&ctx->rambox[idx]; + k = *p; + old+=rf_rotr64(k, (uint8_t) (old/RAMBOX_SIZE)); + *p = (int64_t)old < 0 ? k : old; + } + return (uint32_t)old; +} + +// write (_x_,_y_) at cell _cell_ for offset _ofs_ +static inline void rf_w128(uint64_t *cell, uint64_t ofs, uint64_t x, uint64_t y) { +#if defined(__ARM_ARCH_8A) || defined(__AARCH64EL__) + // 128 bit at once is faster when exactly two parallelizable instructions are + // used between two calls to keep the pipe full. + asm volatile("stp %0, %1, [%2,#%3]\n\t" + : /* no output */ + : "r"(x), "r"(y), "r" (cell), "I" (ofs*8)); +#else + cell[ofs+0] = x; + cell[ofs+1] = y; +#endif +} + +// initialize the ram box +static void rf_raminit(rf256_ctx_t *ctx) { + uint64_t pat1 = 0x0123456789ABCDEFULL; + uint64_t pat2 = 0xFEDCBA9876543210ULL; + uint64_t pat3; + uint32_t pos; + uint64_t *rambox = ctx->rambox; + + // Note: no need to mask the higher bits on armv8 nor x86 : + // + // From ARMv8's ref manual : + // The register that is specified for a shift can be 32-bit or + // 64-bit. The amount to be shifted can be specified either as + // an immediate, that is up to register size minus one, or by + // a register where the value is taken only from the bottom five + // (modulo-32) or six (modulo-64) bits. + // + // Here we rotate pat2 by pat1's bits and put it into pat1, and in + // parallel we rotate pat1 by pat2's bits and put it into pat2. Thus + // the two data blocks are exchanged in addition to being rotated. + // What is stored each time is the previous and the rotated blocks, + // which only requires one rotate and a register rename. + + ctx->changes = 0; + for (pos = 0; pos < RAMBOX_SIZE; pos += 16) { + pat3 = pat1; + pat1 = rf_rotr64(pat2, (uint8_t)pat3) + 0x111; + rf_w128(rambox + pos, 0, pat1, pat3); + + pat3 = pat2; + pat2 = rf_rotr64(pat1, (uint8_t)pat3) + 0x222; + rf_w128(rambox + pos, 2, pat2, pat3); + + pat3 = pat1; + pat1 = rf_rotr64(pat2, (uint8_t)pat3) + 0x333; + rf_w128(rambox + pos, 4, pat1, pat3); + + pat3 = pat2; + pat2 = rf_rotr64(pat1, (uint8_t)pat3) + 0x444; + rf_w128(rambox + pos, 6, pat2, pat3); + + pat3 = pat1; + pat1 = rf_rotr64(pat2, (uint8_t)pat3) + 0x555; + rf_w128(rambox + pos, 8, pat1, pat3); + + pat3 = pat2; + pat2 = rf_rotr64(pat1, (uint8_t)pat3) + 0x666; + rf_w128(rambox + pos, 10, pat2, pat3); + + pat3 = pat1; + pat1 = rf_rotr64(pat2, (uint8_t)pat3) + 0x777; + rf_w128(rambox + pos, 12, pat1, pat3); + + pat3 = pat2; + pat2 = rf_rotr64(pat1, (uint8_t)pat3) + 0x888; + rf_w128(rambox + pos, 14, pat2, pat3); + } +} + +// exec the div/mod box. _v0_ and _v1_ must be aligned. +static inline void rf256_divbox(rf_u64 *v0, rf_u64 *v1) { + uint64_t pl, ql, ph, qh; + + //---- low word ---- ---- high word ---- + pl=~*v0; ph=~*v1; + ql=rf_bswap64(*v0); qh=rf_bswap64(*v1); + + if (!pl||!ql) { pl=ql=0; } + else if (pl>ql) { uint64_t p=pl; pl=p/ql; ql=p%ql; } + else { uint64_t p=pl; pl=ql/p; ql=ql%p; } + + if (!ph||!qh) { ph=qh=0; } + else if (ph>qh) { uint64_t p=ph; ph=p/qh; qh=p%qh; } + else { uint64_t p=ph; ph=qh/p; qh=qh%p; } + + pl+=qh; ph+=ql; + *v0-=pl; *v1-=ph; +} + +// exec the rotation/add box. _v0_ and _v1_ must be aligned. +static inline void rf256_rotbox(rf_u64 *v0, rf_u64 *v1, uint8_t b0, uint8_t b1) { + uint64_t l, h; + + //---- low word ---- ---- high word ---- + l=*v0; h=*v1; + l=rf_rotr64(l,b0); h=rf_rotl64(h,b1); + l+=rf_wltable(b0); h+=rf_whtable(b1); + b0=(uint8_t)l; b1=(uint8_t)h; + l=rf_rotl64(l,b1); h=rf_rotr64(h,b0); + b0=(uint8_t)l; b1=(uint8_t)h; + l=rf_rotr64(l,b1); h=rf_rotl64(h,b0); + *v0=l; *v1=h; +} + +// mix the current state with the current crc +static inline uint32_t rf256_scramble(rf256_ctx_t *ctx) { + return ctx->crc=rf_crc32x4(ctx->hash.d, ctx->crc); +} + +// mix the state with the crc and the pending text, and update the crc +static inline void rf256_inject(rf256_ctx_t *ctx) { + // BS: never <4 bytes with 80 input bytes + //ctx->crc= + // (ctx->bytes&3)==0?rf_crc32_32(rf256_scramble(ctx), ctx->word): + // (ctx->bytes&3)==3?rf_crc32_24(rf256_scramble(ctx), ctx->word): + // (ctx->bytes&3)==2?rf_crc32_16(rf256_scramble(ctx), ctx->word): + // rf_crc32_8(rf256_scramble(ctx), ctx->word); + ctx->crc=rf_crc32_32(rf256_scramble(ctx), ctx->word); + ctx->word=0; +} + +// rotate the hash by 32 bits. Not using streaming instructions (SSE/NEON) is +// faster because the compiler can follow moves an use register renames. +static inline void rf256_rot32x256(hash256_t *hash) { +#if defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_ARCH_7A__) + uint32_t t0, t1, t2; + + t0=hash->d[0]; + t1=hash->d[1]; + t2=hash->d[2]; + hash->d[1]=t0; + hash->d[2]=t1; + + t0=hash->d[3]; + t1=hash->d[4]; + hash->d[3]=t2; + hash->d[4]=t0; + + t2=hash->d[5]; + t0=hash->d[6]; + hash->d[5]=t1; + hash->d[6]=t2; + + t1=hash->d[7]; + hash->d[7]=t0; + hash->d[0]=t1; +#else + uint32_t tmp=hash->d[7]; + + memmove(&hash->d[1], &hash->d[0], 28); + hash->d[0]=tmp; +#endif +} + +// encrypt the first 128 bits of the hash using the last 128 bits as the key +static inline void rf256_aesenc(rf256_ctx_t *ctx) { + aes2r_encrypt((uint8_t *)ctx->hash.b, (uint8_t *)ctx->hash.b+16); +} + +// each new round consumes exactly 32 bits of text at once and perturbates +// 128 bits of output, 96 of which overlap with the previous round, and 32 +// of which are new. With 5 rounds or more each output bit depends on every +// input bit. +static inline void rf256_one_round(rf256_ctx_t *ctx) { + uint64_t carry; + + rf256_rot32x256(&ctx->hash); + + carry=((uint64_t)ctx->len << 32) + ctx->crc; + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + + carry=rf_rambox(ctx, carry); + rf256_rotbox(ctx->hash.q, ctx->hash.q+1, (uint8_t)carry, (uint8_t) (carry>>56)); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + + carry=rf_rambox(ctx, carry); + rf256_rotbox(ctx->hash.q, ctx->hash.q+1, (uint8_t)(carry>>8), (uint8_t) (carry>>48)); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + + carry=rf_rambox(ctx, carry); + rf256_rotbox(ctx->hash.q, ctx->hash.q+1, (uint8_t)(carry>>16), (uint8_t) (carry>>40)); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_scramble(ctx); + + carry=rf_rambox(ctx,carry); + rf256_rotbox(ctx->hash.q, ctx->hash.q+1, (uint8_t)(carry>>24), (uint8_t) (carry>>32)); + rf256_scramble(ctx); + rf256_divbox(ctx->hash.q, ctx->hash.q+1); + rf256_inject(ctx); + rf256_aesenc(ctx); + rf256_scramble(ctx); +} + +// initialize the hash state +static void rf256_init(rf256_ctx_t *ctx) { + rf_raminit(ctx); + memcpy(ctx->hash.b, rf256_iv, sizeof(ctx->hash.b)); + ctx->crc=RF256_INIT_CRC; + ctx->word=ctx->len=0; +} + +// update the hash context _ctx_ with _len_ bytes from message _msg_ +static void rf256_update(rf256_ctx_t *ctx, const void *msg, size_t len) { + const uint8_t* ptr = (uint8_t*)msg; + while (len > 0) { +#ifdef RF_UNALIGNED_LE32 + if (!(ctx->len&3) && len>=4) { + ctx->word=*(uint32_t*)ptr; + ctx->len+=4; + rf256_one_round(ctx); + ptr+=4; + len-=4; + continue; + } +#endif + ctx->word |= (uint32_t)*(ptr++) << (8 * (ctx->len++ & 3)); + len--; + if (!(ctx->len&3)) + rf256_one_round(ctx); + } +} + +// finalize the hash and copy the result into _out_ if not null (256 bits) +static void rf256_final(void *out, rf256_ctx_t *ctx) { + // BS: never happens with 80 input bytes + //uint32_t pad; + + //if (ctx->len&3) + // rf256_one_round(ctx); + + // always work on at least 256 bits of input + //for (pad=0; pad+ctx->len < 32;pad+=4) + // rf256_one_round(ctx); + + // always run 4 extra rounds to complete the last 128 bits + rf256_one_round(ctx); + rf256_one_round(ctx); + rf256_one_round(ctx); + rf256_one_round(ctx); + //if (out) + memcpy(out, ctx->hash.b, 32); +} + +// hash _len_ bytes from _in_ into _out_ +void rf256_hash(void *out, const void *in, size_t len) +{ + rf256_ctx_t ctx; + rf256_init(&ctx); + rf256_update(&ctx, in, len); + rf256_final(out, &ctx); +} + +int scanhash_rf256(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + rf256_ctx_t ctx, ctx_common; + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + //printf("thd%d work=%p htarg=%08x ptarg7=%08x first_nonce=%08x max_nonce=%08x hashes_done=%Lu\n", + // thr_id, work, Htarg, ptarget[7], first_nonce, max_nonce, (unsigned long)*hashes_done); + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + // pre-compute the hash state based on the constant part of the header + rf256_init(&ctx_common); + rf256_update(&ctx_common, endiandata, 76); + ctx_common.changes = 0; + + memcpy(&ctx, &ctx_common, sizeof(ctx)); + + do { + be32enc(&endiandata[19], nonce); +#ifndef RF_DISABLE_CTX_MEMCPY +#ifndef RF_DISABLE_CTX_HISTORY + if (ctx.changes == RAMBOX_HIST) + memcpy(&ctx, &ctx_common, sizeof(ctx)); + else { + for (int i=0; i +#include +#include +#include + +#include "sha3/sph_skein.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" + +void s3hash(void *output, const void *input) +{ + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_skein512_context ctx_skein; + + unsigned char _ALIGN(128) hash[64]; + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, input, 80); + sph_shavite512_close(&ctx_shavite, (void*)hash); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, (const void*)hash, 64); + sph_simd512_close(&ctx_simd, (void*)hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, (const void*)hash, 64); + sph_skein512_close(&ctx_skein, (void*)hash); + + memcpy(output, hash, 32); +} + +int scanhash_s3(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + uint32_t n = pdata[19] - 1; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + s3hash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return true; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return true; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/scrypt-jane.c b/algo/scrypt-jane.c new file mode 100644 index 000000000..6089877ec --- /dev/null +++ b/algo/scrypt-jane.c @@ -0,0 +1,224 @@ +#include "miner.h" + +#include +#include +#include "inttypes.h" + +/* Hard-coded scrypt parameteres r and p - mikaelh */ +#define SCRYPT_R 1 +#define SCRYPT_P 1 + +/* Only the instrinsics versions are optimized for hard-coded values - mikaelh */ +#define CPU_X86_FORCE_INTRINSICS + +#undef SCRYPT_KECCAK512 +#undef SCRYPT_CHACHA +#undef SCRYPT_CHOOSE_COMPILETIME +#define SCRYPT_KECCAK512 +#define SCRYPT_CHACHA +#define SCRYPT_CHOOSE_COMPILETIME + +//#include "scrypt-jane.h" +#include "../scryptjane/scrypt-jane-portable.h" +#include "../scryptjane/scrypt-jane-hash.h" +#include "../scryptjane/scrypt-jane-romix.h" +#include "../scryptjane/scrypt-jane-test-vectors.h" + + +#define scrypt_maxN 30 /* (1 << (30 + 1)) = ~2 billion */ +#if (SCRYPT_BLOCK_BYTES == 64) +#define scrypt_r_32kb 8 /* (1 << 8) = 256 * 2 blocks in a chunk * 64 bytes = Max of 32kb in a chunk */ +#elif (SCRYPT_BLOCK_BYTES == 128) +#define scrypt_r_32kb 7 /* (1 << 7) = 128 * 2 blocks in a chunk * 128 bytes = Max of 32kb in a chunk */ +#elif (SCRYPT_BLOCK_BYTES == 256) +#define scrypt_r_32kb 6 /* (1 << 6) = 64 * 2 blocks in a chunk * 256 bytes = Max of 32kb in a chunk */ +#elif (SCRYPT_BLOCK_BYTES == 512) +#define scrypt_r_32kb 5 /* (1 << 5) = 32 * 2 blocks in a chunk * 512 bytes = Max of 32kb in a chunk */ +#endif +#define scrypt_maxr scrypt_r_32kb /* 32kb */ +#define scrypt_maxp 25 /* (1 << 25) = ~33 million */ + +typedef struct scrypt_aligned_alloc_t { + uint8_t *mem, *ptr; +} scrypt_aligned_alloc; + +static int +scrypt_alloc(uint64_t size, scrypt_aligned_alloc *aa) { + static const size_t max_alloc = (size_t)-1; + size += (SCRYPT_BLOCK_BYTES - 1); + if (size > max_alloc) + return 0; // scrypt_fatal_error("scrypt: not enough address space on this CPU to allocate required memory"); + aa->mem = (uint8_t *)malloc((size_t)size); + aa->ptr = (uint8_t *)(((size_t)aa->mem + (SCRYPT_BLOCK_BYTES - 1)) & ~(SCRYPT_BLOCK_BYTES - 1)); + if (!aa->mem) + return 0; // scrypt_fatal_error("scrypt: out of memory"); + return 1; +} + +static void +scrypt_free(scrypt_aligned_alloc *aa) { + free(aa->mem); +} + +void +scrypt_N_1_1(const uint8_t *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t N, uint8_t *out, size_t bytes, uint8_t *X, uint8_t *Y, uint8_t *V) { + uint32_t chunk_bytes, i; + const uint32_t r = SCRYPT_R; + const uint32_t p = SCRYPT_P; + +#if !defined(SCRYPT_CHOOSE_COMPILETIME) + scrypt_ROMixfn scrypt_ROMix = scrypt_getROMix(); +#endif + + chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; + + /* 1: X = PBKDF2(password, salt) */ + scrypt_pbkdf2_1(password, password_len, salt, salt_len, X, chunk_bytes * p); + + /* 2: X = ROMix(X) */ + for (i = 0; i < p; i++) + scrypt_ROMix_1((scrypt_mix_word_t *)(X + (chunk_bytes * i)), (scrypt_mix_word_t *)Y, (scrypt_mix_word_t *)V, N); + + /* 3: Out = PBKDF2(password, X) */ + scrypt_pbkdf2_1(password, password_len, X, chunk_bytes * p, out, bytes); + +#ifdef SCRYPT_PREVENT_STATE_LEAK + /* This is an unnecessary security feature - mikaelh */ + scrypt_ensure_zero(Y, (p + 1) * chunk_bytes); +#endif +} + + +// increasing Nfactor gradually +const unsigned char minNfactor = 4; +const unsigned char maxNfactor = 30; + +unsigned char GetNfactor(unsigned int nTimestamp, unsigned int ntime) { + int l = 0; + unsigned long int s; + int n; + unsigned char N; + + if (nTimestamp <= ntime) + return 4; + + s = nTimestamp - ntime; + while ((s >> 1) > 3) { + l += 1; + s >>= 1; + } + + s &= 3; + + n = (l * 170 + s * 25 - 2320) / 100; + + if (n < 0) n = 0; + + if (n > 255) { + n = 255; + // printf("GetNfactor(%d) - something wrong(n == %d)\n", nTimestamp, n); + } + + N = (unsigned char)n; + //printf("GetNfactor: %d -> %d %d : %d / %d\n", nTimestamp - nChainStartTime, l, s, n, min(max(N, minNfactor), maxNfactor)); + + if (NmaxNfactor) return maxNfactor; + return N; +} + + +int scanhash_scryptjane(int Nfactor, int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + scrypt_aligned_alloc YX, V; + uint8_t *X, *Y; + uint32_t N, chunk_bytes; + const uint32_t r = SCRYPT_R; + const uint32_t p = SCRYPT_P; + + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + uint32_t _ALIGN(64) endiandata[20]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + + if (opt_benchmark) + ptarget[7] = 0x00ff; + + for (int k = 0; k < 20; k++) + be32enc(&endiandata[k], pdata[k]); + + //Nfactor = GetNfactor(data[17], ntime); + //if (Nfactor > scrypt_maxN) { + // return 1; + // //scrypt_fatal_error("scrypt: N out of range"); + //} + + N = (1 << (Nfactor + 1)); + + chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; + if (!scrypt_alloc((uint64_t)N * chunk_bytes, &V)) return 1; + if (!scrypt_alloc((p + 1) * chunk_bytes, &YX)) { + scrypt_free(&V); + return 1; + } + + Y = YX.ptr; + X = Y + chunk_bytes; + + do { + const uint32_t Htarg = ptarget[7]; + uint32_t hash[8]; + be32enc(&endiandata[19], nonce); + + scrypt_N_1_1((unsigned char *)endiandata, 80, + (unsigned char *)endiandata, 80, + N, (unsigned char *)hash, 32, X, Y, V.ptr); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + scrypt_free(&V); + scrypt_free(&YX); + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + + scrypt_free(&V); + scrypt_free(&YX); + return 0; +} + +/* simple cpu test (util.c) */ +void scryptjanehash(void *output, const void *input, uint32_t Nfactor) +{ + scrypt_aligned_alloc YX, V; + uint8_t *X, *Y; + uint32_t chunk_bytes; + uint32_t N = (1 << (Nfactor + 1)); + const uint32_t r = SCRYPT_R; + const uint32_t p = SCRYPT_P; + + memset(output, 0, 32); + + chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; + if (!scrypt_alloc((uint64_t)N * chunk_bytes, &V)) return; + if (!scrypt_alloc((p + 1) * chunk_bytes, &YX)) { + scrypt_free(&V); + return; + } + + Y = YX.ptr; + X = Y + chunk_bytes; + + scrypt_N_1_1((unsigned char*)input, 80, (unsigned char*)input, 80, + N, (unsigned char*)output, 32, X, Y, V.ptr); + + scrypt_free(&V); + scrypt_free(&YX); +} diff --git a/scrypt.c b/algo/scrypt.c similarity index 92% rename from scrypt.c rename to algo/scrypt.c index 0b31a9355..84e12ae96 100644 --- a/scrypt.c +++ b/algo/scrypt.c @@ -27,7 +27,6 @@ * online backup system. */ -#include "cpuminer-config.h" #include "miner.h" #include @@ -158,7 +157,7 @@ static const uint32_t outerpad_4way[4 * 8] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000300, 0x00000300, 0x00000300, 0x00000300 }; -static const uint32_t finalblk_4way[4 * 16] __attribute__((aligned(16))) = { +static const uint32_t _ALIGN(16) finalblk_4way[4 * 16] = { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -180,8 +179,8 @@ static const uint32_t finalblk_4way[4 * 16] __attribute__((aligned(16))) = { static inline void HMAC_SHA256_80_init_4way(const uint32_t *key, uint32_t *tstate, uint32_t *ostate) { - uint32_t ihash[4 * 8] __attribute__((aligned(16))); - uint32_t pad[4 * 16] __attribute__((aligned(16))); + uint32_t _ALIGN(16) ihash[4 * 8]; + uint32_t _ALIGN(16) pad[4 * 16]; int i; /* tstate is assumed to contain the midstate of key */ @@ -208,10 +207,10 @@ static inline void HMAC_SHA256_80_init_4way(const uint32_t *key, static inline void PBKDF2_SHA256_80_128_4way(const uint32_t *tstate, const uint32_t *ostate, const uint32_t *salt, uint32_t *output) { - uint32_t istate[4 * 8] __attribute__((aligned(16))); - uint32_t ostate2[4 * 8] __attribute__((aligned(16))); - uint32_t ibuf[4 * 16] __attribute__((aligned(16))); - uint32_t obuf[4 * 16] __attribute__((aligned(16))); + uint32_t _ALIGN(16) istate[4 * 8]; + uint32_t _ALIGN(16) ostate2[4 * 8]; + uint32_t _ALIGN(16) ibuf[4 * 16]; + uint32_t _ALIGN(16) obuf[4 * 16]; int i, j; memcpy(istate, tstate, 4 * 32); @@ -239,7 +238,7 @@ static inline void PBKDF2_SHA256_80_128_4way(const uint32_t *tstate, static inline void PBKDF2_SHA256_128_32_4way(uint32_t *tstate, uint32_t *ostate, const uint32_t *salt, uint32_t *output) { - uint32_t buf[4 * 16] __attribute__((aligned(16))); + uint32_t _ALIGN(16) buf[4 * 16]; int i; sha256_transform_4way(tstate, salt, 1); @@ -258,7 +257,7 @@ static inline void PBKDF2_SHA256_128_32_4way(uint32_t *tstate, #ifdef HAVE_SHA256_8WAY -static const uint32_t finalblk_8way[8 * 16] __attribute__((aligned(32))) = { +static const uint32_t _ALIGN(32) finalblk_8way[8 * 16] = { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -280,8 +279,8 @@ static const uint32_t finalblk_8way[8 * 16] __attribute__((aligned(32))) = { static inline void HMAC_SHA256_80_init_8way(const uint32_t *key, uint32_t *tstate, uint32_t *ostate) { - uint32_t ihash[8 * 8] __attribute__((aligned(32))); - uint32_t pad[8 * 16] __attribute__((aligned(32))); + uint32_t _ALIGN(32) ihash[8 * 8]; + uint32_t _ALIGN(32) pad[8 * 16]; int i; /* tstate is assumed to contain the midstate of key */ @@ -312,10 +311,10 @@ static inline void HMAC_SHA256_80_init_8way(const uint32_t *key, static inline void PBKDF2_SHA256_80_128_8way(const uint32_t *tstate, const uint32_t *ostate, const uint32_t *salt, uint32_t *output) { - uint32_t istate[8 * 8] __attribute__((aligned(32))); - uint32_t ostate2[8 * 8] __attribute__((aligned(32))); - uint32_t ibuf[8 * 16] __attribute__((aligned(32))); - uint32_t obuf[8 * 16] __attribute__((aligned(32))); + uint32_t _ALIGN(32) istate[8 * 8]; + uint32_t _ALIGN(32) ostate2[8 * 8]; + uint32_t _ALIGN(32) ibuf[8 * 16]; + uint32_t _ALIGN(32) obuf[8 * 16]; int i, j; memcpy(istate, tstate, 8 * 32); @@ -356,7 +355,7 @@ static inline void PBKDF2_SHA256_80_128_8way(const uint32_t *tstate, static inline void PBKDF2_SHA256_128_32_8way(uint32_t *tstate, uint32_t *ostate, const uint32_t *salt, uint32_t *output) { - uint32_t buf[8 * 16] __attribute__((aligned(32))); + uint32_t _ALIGN(32) buf[8 * 16]; int i; sha256_transform_8way(tstate, salt, 1); @@ -481,16 +480,16 @@ static inline void xor_salsa8(uint32_t B[16], const uint32_t Bx[16]) static inline void scrypt_core(uint32_t *X, uint32_t *V, int N) { - uint32_t i, j, k; - + int i; + for (i = 0; i < N; i++) { memcpy(&V[i * 32], X, 128); xor_salsa8(&X[0], &X[16]); xor_salsa8(&X[16], &X[0]); } for (i = 0; i < N; i++) { - j = 32 * (X[16] & (N - 1)); - for (k = 0; k < 32; k++) + uint32_t j = 32 * (X[16] & (N - 1)); + for (uint8_t k = 0; k < 32; k++) X[k] ^= V[j + k]; xor_salsa8(&X[0], &X[16]); xor_salsa8(&X[16], &X[0]); @@ -506,7 +505,7 @@ static inline void scrypt_core(uint32_t *X, uint32_t *V, int N) unsigned char *scrypt_buffer_alloc(int N) { - return malloc((size_t)N * SCRYPT_MAX_WAYS * 128 + 63); + return (uchar*) malloc((size_t)N * SCRYPT_MAX_WAYS * 128 + 63); } static void scrypt_1024_1_1_256(const uint32_t *input, uint32_t *output, @@ -531,10 +530,10 @@ static void scrypt_1024_1_1_256(const uint32_t *input, uint32_t *output, static void scrypt_1024_1_1_256_4way(const uint32_t *input, uint32_t *output, uint32_t *midstate, unsigned char *scratchpad, int N) { - uint32_t tstate[4 * 8] __attribute__((aligned(128))); - uint32_t ostate[4 * 8] __attribute__((aligned(128))); - uint32_t W[4 * 32] __attribute__((aligned(128))); - uint32_t X[4 * 32] __attribute__((aligned(128))); + uint32_t _ALIGN(128) tstate[4 * 8]; + uint32_t _ALIGN(128) ostate[4 * 8]; + uint32_t _ALIGN(128) W[4 * 32]; + uint32_t _ALIGN(128) X[4 * 32]; uint32_t *V; int i, k; @@ -570,8 +569,8 @@ static void scrypt_1024_1_1_256_4way(const uint32_t *input, static void scrypt_1024_1_1_256_3way(const uint32_t *input, uint32_t *output, uint32_t *midstate, unsigned char *scratchpad, int N) { - uint32_t tstate[3 * 8], ostate[3 * 8]; - uint32_t X[3 * 32] __attribute__((aligned(64))); + uint32_t _ALIGN(64) tstate[3 * 8], ostate[3 * 8]; + uint32_t _ALIGN(64) X[3 * 32]; uint32_t *V; V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); @@ -597,10 +596,10 @@ static void scrypt_1024_1_1_256_3way(const uint32_t *input, static void scrypt_1024_1_1_256_12way(const uint32_t *input, uint32_t *output, uint32_t *midstate, unsigned char *scratchpad, int N) { - uint32_t tstate[12 * 8] __attribute__((aligned(128))); - uint32_t ostate[12 * 8] __attribute__((aligned(128))); - uint32_t W[12 * 32] __attribute__((aligned(128))); - uint32_t X[12 * 32] __attribute__((aligned(128))); + uint32_t _ALIGN(128) tstate[12 * 8]; + uint32_t _ALIGN(128) ostate[12 * 8]; + uint32_t _ALIGN(128) W[12 * 32]; + uint32_t _ALIGN(128) X[12 * 32]; uint32_t *V; int i, j, k; @@ -648,10 +647,10 @@ static void scrypt_1024_1_1_256_12way(const uint32_t *input, static void scrypt_1024_1_1_256_24way(const uint32_t *input, uint32_t *output, uint32_t *midstate, unsigned char *scratchpad, int N) { - uint32_t tstate[24 * 8] __attribute__((aligned(128))); - uint32_t ostate[24 * 8] __attribute__((aligned(128))); - uint32_t W[24 * 32] __attribute__((aligned(128))); - uint32_t X[24 * 32] __attribute__((aligned(128))); + uint32_t _ALIGN(128) tstate[24 * 8]; + uint32_t _ALIGN(128) ostate[24 * 8]; + uint32_t _ALIGN(128) W[24 * 32]; + uint32_t _ALIGN(128) X[24 * 32]; uint32_t *V; int i, j, k; @@ -693,10 +692,11 @@ static void scrypt_1024_1_1_256_24way(const uint32_t *input, } #endif /* HAVE_SCRYPT_6WAY */ -int scanhash_scrypt(int thr_id, uint32_t *pdata, - unsigned char *scratchbuf, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done, int N) +extern int scanhash_scrypt(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, + unsigned char *scratchbuf, uint32_t N) { + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; uint32_t data[SCRYPT_MAX_WAYS * 20], hash[SCRYPT_MAX_WAYS * 8]; uint32_t midstate[8]; uint32_t n = pdata[19] - 1; @@ -743,6 +743,7 @@ int scanhash_scrypt(int thr_id, uint32_t *pdata, for (i = 0; i < throughput; i++) { if (unlikely(hash[i * 8 + 7] <= Htarg && fulltest(hash + i * 8, ptarget))) { + work_set_target_ratio(work, hash + i * 8); *hashes_done = n - pdata[19] + 1; pdata[19] = data[i * 20 + 19]; return 1; @@ -754,3 +755,21 @@ int scanhash_scrypt(int thr_id, uint32_t *pdata, pdata[19] = n; return 0; } + +/* simple cpu test (util.c) */ +void scrypthash(void *output, const void *input, uint32_t N) +{ + uint32_t midstate[8]; + char *scratchbuf = scrypt_buffer_alloc(N); + + memset(output, 0, 32); + if (!scratchbuf) + return; + + sha256_init(midstate); + sha256_transform(midstate, input, 0); + + scrypt_1024_1_1_256((uint32_t*)input, (uint32_t*)output, midstate, scratchbuf, N); + + free(scratchbuf); +} diff --git a/sha2.c b/algo/sha2.c similarity index 92% rename from sha2.c rename to algo/sha2.c index 67c909dbd..8625c4830 100644 --- a/sha2.c +++ b/algo/sha2.c @@ -8,7 +8,6 @@ * any later version. See COPYING for more details. */ -#include "cpuminer-config.h" #include "miner.h" #include @@ -196,7 +195,7 @@ static void sha256d_80_swap(uint32_t *hash, const uint32_t *data) hash[i] = swab32(hash[i]); } -void sha256d(unsigned char *hash, const unsigned char *data, int len) +extern void sha256d(unsigned char *hash, const unsigned char *data, int len) { uint32_t S[16], T[16]; int i, r; @@ -468,13 +467,15 @@ static inline void sha256d_ms(uint32_t *hash, uint32_t *W, void sha256d_ms_4way(uint32_t *hash, uint32_t *data, const uint32_t *midstate, const uint32_t *prehash); -static inline int scanhash_sha256d_4way(int thr_id, uint32_t *pdata, - const uint32_t *ptarget, uint32_t max_nonce, uint64_t *hashes_done) +static inline int scanhash_sha256d_4way(int thr_id, struct work *work, + uint32_t max_nonce, uint64_t *hashes_done) { - uint32_t data[4 * 64] __attribute__((aligned(128))); - uint32_t hash[4 * 8] __attribute__((aligned(32))); - uint32_t midstate[4 * 8] __attribute__((aligned(32))); - uint32_t prehash[4 * 8] __attribute__((aligned(32))); + uint32_t _ALIGN(128) data[4 * 64]; + uint32_t _ALIGN(32) hash[4 * 8]; + uint32_t _ALIGN(32) midstate[4 * 8]; + uint32_t _ALIGN(32) prehash[4 * 8]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; uint32_t n = pdata[19] - 1; const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; @@ -508,6 +509,7 @@ static inline int scanhash_sha256d_4way(int thr_id, uint32_t *pdata, pdata[19] = data[4 * 3 + i]; sha256d_80_swap(hash, pdata); if (fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); *hashes_done = n - first_nonce + 1; return 1; } @@ -527,13 +529,15 @@ static inline int scanhash_sha256d_4way(int thr_id, uint32_t *pdata, void sha256d_ms_8way(uint32_t *hash, uint32_t *data, const uint32_t *midstate, const uint32_t *prehash); -static inline int scanhash_sha256d_8way(int thr_id, uint32_t *pdata, - const uint32_t *ptarget, uint32_t max_nonce, uint64_t *hashes_done) +static inline int scanhash_sha256d_8way(int thr_id, struct work *work, + uint32_t max_nonce, uint64_t *hashes_done) { - uint32_t data[8 * 64] __attribute__((aligned(128))); - uint32_t hash[8 * 8] __attribute__((aligned(32))); - uint32_t midstate[8 * 8] __attribute__((aligned(32))); - uint32_t prehash[8 * 8] __attribute__((aligned(32))); + uint32_t _ALIGN(128) data[8 * 64]; + uint32_t _ALIGN(32) hash[8 * 8]; + uint32_t _ALIGN(32) midstate[8 * 8]; + uint32_t _ALIGN(32) prehash[8 * 8]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; uint32_t n = pdata[19] - 1; const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; @@ -567,6 +571,7 @@ static inline int scanhash_sha256d_8way(int thr_id, uint32_t *pdata, pdata[19] = data[8 * 3 + i]; sha256d_80_swap(hash, pdata); if (fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); *hashes_done = n - first_nonce + 1; return 1; } @@ -581,26 +586,25 @@ static inline int scanhash_sha256d_8way(int thr_id, uint32_t *pdata, #endif /* HAVE_SHA256_8WAY */ -int scanhash_sha256d(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) +int scanhash_sha256d(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) { - uint32_t data[64] __attribute__((aligned(128))); - uint32_t hash[8] __attribute__((aligned(32))); - uint32_t midstate[8] __attribute__((aligned(32))); - uint32_t prehash[8] __attribute__((aligned(32))); - uint32_t n = pdata[19] - 1; + uint32_t _ALIGN(128) data[64]; + uint32_t _ALIGN(32) hash[8]; + uint32_t _ALIGN(32) midstate[8]; + uint32_t _ALIGN(32) prehash[8]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; - + uint32_t n = pdata[19] - 1; + #ifdef HAVE_SHA256_8WAY if (sha256_use_8way()) - return scanhash_sha256d_8way(thr_id, pdata, ptarget, - max_nonce, hashes_done); + return scanhash_sha256d_8way(thr_id, work, max_nonce, hashes_done); #endif #ifdef HAVE_SHA256_4WAY if (sha256_use_4way()) - return scanhash_sha256d_4way(thr_id, pdata, ptarget, - max_nonce, hashes_done); + return scanhash_sha256d_4way(thr_id, work, max_nonce, hashes_done); #endif memcpy(data, pdata + 16, 64); @@ -618,6 +622,7 @@ int scanhash_sha256d(int thr_id, uint32_t *pdata, const uint32_t *ptarget, pdata[19] = data[3]; sha256d_80_swap(hash, pdata); if (fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); *hashes_done = n - first_nonce + 1; return 1; } diff --git a/algo/sia.c b/algo/sia.c new file mode 100644 index 000000000..a7a9e5cfc --- /dev/null +++ b/algo/sia.c @@ -0,0 +1,134 @@ +/** + * Blake2-B Implementation + * tpruvot@github 2015-2016 + */ + +#include "miner.h" + +#include +#include + +#include + +#define A 64 + +#ifdef MIDSTATE +static __thread blake2b_ctx s_midstate; +static __thread blake2b_ctx s_ctx; +#define MIDLEN 76 + +static void blake2b_hash_end(uint32_t *output, const uint32_t *input) +{ + s_ctx.outlen = MIDLEN; + memcpy(&s_ctx, &s_midstate, 32 + 16 + MIDLEN); + blake2b_update(&s_ctx, (uint8_t*) &input[MIDLEN/4], 80 - MIDLEN); + blake2b_final(&s_ctx, (uint8_t*) output); +} +#endif + +void blake2b_hash(void *output, const void *input) +{ + uint8_t _ALIGN(A) hash[32]; + blake2b_ctx ctx; + + blake2b_init(&ctx, 32, NULL, 0); + blake2b_update(&ctx, input, 80); + blake2b_final(&ctx, hash); + + memcpy(output, hash, 32); +} + +int scanhash_blake2b(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(A) vhashcpu[8]; + uint32_t _ALIGN(A) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + // midstate (untested yet) + //blake2b_init(&s_midstate, 32, NULL, 0); + //blake2b_update(&s_midstate, (uint8_t*) endiandata, MIDLEN); + //memcpy(&s_ctx, &s_midstate, sizeof(blake2b_ctx)); + + do { + be32enc(&endiandata[19], n); + //blake2b_hash_end(vhashcpu, endiandata); + blake2b_hash(vhashcpu, endiandata); + + if (vhashcpu[7] < Htarg && fulltest(vhashcpu, ptarget)) { + work_set_target_ratio(work, vhashcpu); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 1; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} + +static inline void swab256(void *dest_p, const void *src_p) +{ + uint32_t *dest = (uint32_t *)dest_p; + const uint32_t *src = (uint32_t *)src_p; + + dest[0] = swab32(src[7]); + dest[1] = swab32(src[6]); + dest[2] = swab32(src[5]); + dest[3] = swab32(src[4]); + dest[4] = swab32(src[3]); + dest[5] = swab32(src[2]); + dest[6] = swab32(src[1]); + dest[7] = swab32(src[0]); +} + +int scanhash_sia(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(A) hash[8]; + uint32_t _ALIGN(A) vhashcpu[8]; + uint32_t _ALIGN(A) inputdata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[8]; + + uint32_t n = first_nonce; + + memcpy(inputdata, pdata, 80); + inputdata[11] = 0; // nbits + + do { + inputdata[8] = n; + blake2b_hash(hash, inputdata); + if (swab32(hash[0]) < Htarg) { + swab256(vhashcpu, hash); + if (fulltest(vhashcpu, ptarget)) { + work_set_target_ratio(work, vhashcpu); + *hashes_done = n - first_nonce + 1; + pdata[8] = n; + return 1; + } + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[8] = n; + + return 0; +} diff --git a/algo/sibcoin.c b/algo/sibcoin.c new file mode 100644 index 000000000..5006897ba --- /dev/null +++ b/algo/sibcoin.c @@ -0,0 +1,127 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_luffa.h" +#include "sha3/gost_streebog.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" + +/* Move init out of loop, so init once externally, and then use one single memcpy with that bigger memory block */ +void sibhash(void *output, const void *input) +{ + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_gost512_context ctx_gost; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + + //these uint512 in the c++ source of the client are backed by an array of uint32 + uint32_t _ALIGN(64) hashA[16], hashB[16]; + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, hashA); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hashA, 64); + sph_bmw512_close(&ctx_bmw, hashB); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hashB, 64); + sph_groestl512_close(&ctx_groestl, hashA); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hashA, 64); + sph_skein512_close(&ctx_skein, hashB); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hashB, 64); + sph_jh512_close(&ctx_jh, hashA); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hashA, 64); + sph_keccak512_close(&ctx_keccak, hashB); + + sph_gost512_init(&ctx_gost); + sph_gost512(&ctx_gost, hashB, 64); + sph_gost512_close(&ctx_gost, hashA); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hashA, 64); + sph_luffa512_close(&ctx_luffa, hashB); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hashB, 64); + sph_cubehash512_close(&ctx_cubehash, hashA); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hashA, 64); + sph_shavite512_close(&ctx_shavite, hashB); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hashB, 64); + sph_simd512_close(&ctx_simd, hashA); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hashA, 64); + sph_echo512_close(&ctx_echo, hashB); + + memcpy(output, hashB, 32); +} + +int scanhash_sib(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + do { + be32enc(&endiandata[19], nonce); + sibhash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/skein.c b/algo/skein.c new file mode 100644 index 000000000..8721294b9 --- /dev/null +++ b/algo/skein.c @@ -0,0 +1,61 @@ +#include "miner.h" + +#include +#include + +#include + +#include "sha3/sph_skein.h" + +void skeinhash(void *state, const void *input) +{ + sph_skein512_context ctx_skein; + SHA256_CTX sha256; + + uint32_t hash[16]; + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, input, 80); + sph_skein512_close(&ctx_skein, hash); + + SHA256_Init(&sha256); + SHA256_Update(&sha256, hash, 64); + SHA256_Final((unsigned char*) hash, &sha256); + + memcpy(state, hash, 32); +} + +int scanhash_skein(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + }; + + do { + be32enc(&endiandata[19], n); + skeinhash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/skein2.c b/algo/skein2.c new file mode 100644 index 000000000..e5fc6e4c1 --- /dev/null +++ b/algo/skein2.c @@ -0,0 +1,58 @@ +#include "miner.h" + +#include +#include + +#include "sha3/sph_skein.h" + +void skein2hash(void *output, const void *input) +{ + uint32_t _ALIGN(128) hash[16]; + + sph_skein512_context ctx_skein; + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, input, 80); + sph_skein512_close(&ctx_skein, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + memcpy(output, hash, 32); +} + +int scanhash_skein2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + skein2hash(hash32, endiandata); + if (hash32[7] < Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} diff --git a/algo/sonoa.c b/algo/sonoa.c new file mode 100644 index 000000000..e80384710 --- /dev/null +++ b/algo/sonoa.c @@ -0,0 +1,434 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void sonoa_hash(void *state, const void *input) +{ + uint8_t _ALIGN(128) hash[64]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + sph_shabal512_context ctx_shabal; + sph_whirlpool_context ctx_whirlpool; + sph_sha512_context ctx_sha512; + sph_haval256_5_context ctx_haval; + + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + + + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) hash, 64); + sph_sha512_close(&ctx_sha512,(void*) hash); + + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + + + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + + sph_sha512(&ctx_sha512,(const void*) hash, 64); + sph_sha512_close(&ctx_sha512,(void*) hash); + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval,(const void*) hash, 64); + sph_haval256_5_close(&ctx_haval, hash); + + memcpy(state, hash, 32); +} + +int scanhash_sonoa(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + uint32_t n = pdata[19] - 1; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + sonoa_hash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/timetravel.c b/algo/timetravel.c new file mode 100644 index 000000000..710779cce --- /dev/null +++ b/algo/timetravel.c @@ -0,0 +1,197 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Machinecoin Genesis Timestamp +#define HASH_FUNC_BASE_TIMESTAMP 1389040865 + +#define HASH_FUNC_COUNT 8 +#define HASH_FUNC_COUNT_PERMUTATIONS 40320 + +static __thread uint32_t s_ntime = UINT32_MAX; +static __thread int permutation[HASH_FUNC_COUNT] = { 0 }; + +// helpers +static void swap(int *a, int *b) { + int c = *a; + *a = *b; + *b = c; +} + +static void reverse(int *pbegin, int *pend) { + while ( (pbegin != pend) && (pbegin != --pend) ) + swap(pbegin++, pend); +} + +static void next_permutation(int *pbegin, int *pend) { + if (pbegin == pend) + return; + + int *i = pbegin; + ++i; + if (i == pend) + return; + + i = pend; + --i; + + while (1) { + int *j = i; + --i; + + if (*i < *j) { + int *k = pend; + + while (!(*i < *--k)) + /* pass */; + + swap(i, k); + reverse(j, pend); + return; // true + } + + if (i == pbegin) { + reverse(pbegin, pend); + return; // false + } + } +} + +void timetravel_hash(void *output, const void *input) +{ + uint32_t _ALIGN(64) hash[16 * HASH_FUNC_COUNT]; + uint32_t *hashA, *hashB; + uint32_t dataLen = 64; + uint32_t *work_data = (uint32_t *)input; + const uint32_t timestamp = work_data[17]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + + // We want to permute algorithms. To get started we + // initialize an array with a sorted sequence of unique + // integers where every integer represents its own algorithm. + if (timestamp != s_ntime) { + int steps = (int) (timestamp - HASH_FUNC_BASE_TIMESTAMP) % HASH_FUNC_COUNT_PERMUTATIONS; + for (int i = 0; i < HASH_FUNC_COUNT; i++) { + permutation[i] = i; + } + for (int i = 0; i < steps; i++) { + next_permutation(permutation, permutation + HASH_FUNC_COUNT); + } + s_ntime = timestamp; + } + + for (int i = 0; i < HASH_FUNC_COUNT; i++) { + if (i == 0) { + dataLen = 80; + hashA = work_data; + } else { + dataLen = 64; + hashA = &hash[16 * (i - 1)]; + } + hashB = &hash[16 * i]; + + switch(permutation[i]) { + case 0: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, hashA, dataLen); + sph_blake512_close(&ctx_blake, hashB); + break; + case 1: + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, hashA, dataLen); + sph_bmw512_close(&ctx_bmw, hashB); + break; + case 2: + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, hashA, dataLen); + sph_groestl512_close(&ctx_groestl, hashB); + break; + case 3: + sph_skein512_init(&ctx_skein); + sph_skein512 (&ctx_skein, hashA, dataLen); + sph_skein512_close(&ctx_skein, hashB); + break; + case 4: + sph_jh512_init(&ctx_jh); + sph_jh512 (&ctx_jh, hashA, dataLen); + sph_jh512_close(&ctx_jh, hashB); + break; + case 5: + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, hashA, dataLen); + sph_keccak512_close(&ctx_keccak, hashB); + break; + case 6: + sph_luffa512_init(&ctx_luffa); + sph_luffa512 (&ctx_luffa, hashA, dataLen); + sph_luffa512_close(&ctx_luffa, hashB); + break; + case 7: + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512 (&ctx_cubehash, hashA, dataLen); + sph_cubehash512_close(&ctx_cubehash, hashB); + break; + default: + break; + } + } + + memcpy(output, &hash[16 * (HASH_FUNC_COUNT - 1)], 32); +} + +int scanhash_timetravel(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + timetravel_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/tribus.c b/algo/tribus.c new file mode 100644 index 000000000..2a7167d2b --- /dev/null +++ b/algo/tribus.c @@ -0,0 +1,103 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_echo.h" + +void tribus_hash(void *state, const void *input) +{ + uint8_t _ALIGN(128) hash[64]; + + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_echo512_context ctx_echo; + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, input, 80); + sph_jh512_close(&ctx_jh, (void*) hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, (const void*) hash, 64); + sph_keccak512_close(&ctx_keccak, (void*) hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, (const void*) hash, 64); + sph_echo512_close(&ctx_echo, (void*) hash); + + memcpy(state, hash, 32); +} + +int scanhash_tribus(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; + const uint32_t Htarg = ptarget[7]; + uint32_t n = pdata[19] - 1; + + uint64_t htmax[] = { + 0, + 0xF, + 0xFF, + 0xFFF, + 0xFFFF, + 0x10000000 + }; + uint32_t masks[] = { + 0xFFFFFFFF, + 0xFFFFFFF0, + 0xFFFFFF00, + 0xFFFFF000, + 0xFFFF0000, + 0 + }; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + +#ifdef DEBUG_ALGO + printf("[%d] Htarg=%X\n", thr_id, Htarg); +#endif + for (int m=0; m < 6; m++) { + if (Htarg <= htmax[m]) { + uint32_t mask = masks[m]; + do { + pdata[19] = ++n; + be32enc(&endiandata[19], n); + tribus_hash(hash32, endiandata); +#ifndef DEBUG_ALGO + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } +#else + if (!(n % 0x1000) && !thr_id) printf("."); + if (!(hash32[7] & mask)) { + printf("[%d]",thr_id); + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + *hashes_done = n - first_nonce + 1; + return 1; + } + } +#endif + } while (n < max_nonce && !work_restart[thr_id].restart); + // see blake.c if else to understand the loop on htmax => mask + break; + } + } + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return 0; +} diff --git a/algo/veltor.c b/algo/veltor.c new file mode 100644 index 000000000..cf4e76a60 --- /dev/null +++ b/algo/veltor.c @@ -0,0 +1,94 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Move init out of loop, so init once externally, and then use one single memcpy with that bigger memory block */ +typedef struct { + sph_skein512_context skein1; + sph_shavite512_context shavite1; + sph_shabal512_context shabal1; + sph_gost512_context gost1; +} Xhash_context_holder; + +static __thread Xhash_context_holder base_contexts; +static __thread bool init = false; + +static void init_Xhash_contexts() +{ + sph_skein512_init(&base_contexts.skein1); + sph_shavite512_init(&base_contexts.shavite1); + sph_shabal512_init(&base_contexts.shabal1); + sph_gost512_init(&base_contexts.gost1); + init = true; +} + +void veltor_hash(void *output, const void *input) +{ + Xhash_context_holder ctx; + + uint32_t hashA[16]; + + if (!init) init_Xhash_contexts(); + + memcpy(&ctx, &base_contexts, sizeof(base_contexts)); + + sph_skein512(&ctx.skein1, input, 80); + sph_skein512_close(&ctx.skein1, hashA); + + sph_shavite512(&ctx.shavite1, hashA, 64); + sph_shavite512_close(&ctx.shavite1, hashA); + + sph_shabal512(&ctx.shabal1, hashA, 64); + sph_shabal512_close(&ctx.shabal1, hashA); + + sph_gost512(&ctx.gost1, hashA, 64); + sph_gost512_close(&ctx.gost1, hashA); + + memcpy(output, hashA, 32); +} + +int scanhash_veltor(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + // we need bigendian data... + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + do { + be32enc(&endiandata[19], nonce); + veltor_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x11.c b/algo/x11.c new file mode 100644 index 000000000..6a3bc85d8 --- /dev/null +++ b/algo/x11.c @@ -0,0 +1,121 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_luffa.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" + + +void x11hash(void *output, const void *input) +{ + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + + //these uint512 in the c++ source of the client are backed by an array of uint32 + uint32_t _ALIGN(64) hashA[16], hashB[16]; + + sph_blake512_init(&ctx_blake); + sph_blake512 (&ctx_blake, input, 80); + sph_blake512_close (&ctx_blake, hashA); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, hashA, 64); + sph_bmw512_close(&ctx_bmw, hashB); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, hashB, 64); + sph_groestl512_close(&ctx_groestl, hashA); + + sph_skein512_init(&ctx_skein); + sph_skein512 (&ctx_skein, hashA, 64); + sph_skein512_close (&ctx_skein, hashB); + + sph_jh512_init(&ctx_jh); + sph_jh512 (&ctx_jh, hashB, 64); + sph_jh512_close(&ctx_jh, hashA); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, hashA, 64); + sph_keccak512_close(&ctx_keccak, hashB); + + sph_luffa512_init (&ctx_luffa1); + sph_luffa512 (&ctx_luffa1, hashB, 64); + sph_luffa512_close (&ctx_luffa1, hashA); + + sph_cubehash512_init (&ctx_cubehash1); + sph_cubehash512 (&ctx_cubehash1, hashA, 64); + sph_cubehash512_close(&ctx_cubehash1, hashB); + + sph_shavite512_init (&ctx_shavite1); + sph_shavite512 (&ctx_shavite1, hashB, 64); + sph_shavite512_close(&ctx_shavite1, hashA); + + sph_simd512_init (&ctx_simd1); + sph_simd512 (&ctx_simd1, hashA, 64); + sph_simd512_close(&ctx_simd1, hashB); + + sph_echo512_init (&ctx_echo1); + sph_echo512 (&ctx_echo1, hashB, 64); + sph_echo512_close(&ctx_echo1, hashA); + + memcpy(output, hashA, 32); +} + +int scanhash_x11(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + x11hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x11evo.c b/algo/x11evo.c new file mode 100644 index 000000000..a85b9eb13 --- /dev/null +++ b/algo/x11evo.c @@ -0,0 +1,256 @@ +/** + * X11EVO algo implementation + * + * Trivial implementation by tpruvot@github May 2016 + */ +#include "miner.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum Algo { + BLAKE = 0, + BMW, + GROESTL, + SKEIN, + JH, + KECCAK, + LUFFA, + CUBEHASH, + SHAVITE, + SIMD, + ECHO, + HASH_FUNC_COUNT +}; + +static void swap8(uint8_t *a, uint8_t *b) +{ + uint8_t t = *a; + *a = *b; + *b = t; +} + +static void initPerm(uint8_t n[], int count) +{ + for (int i = 0; i < count; i++) + n[i] = i; +} + +static int nextPerm(uint8_t n[], int count) +{ + int tail, i, j; + + if (count <= 1) + return 0; + + for (i = count - 1; i>0 && n[i - 1] >= n[i]; i--); + tail = i; + + if (tail > 0) { + for (j = count - 1; j>tail && n[j] <= n[tail - 1]; j--); + swap8(&n[tail - 1], &n[j]); + } + + for (i = tail, j = count - 1; i= 10) + sprintf(sptr, "%c", 'A' + (algoList[j] - 10)); + else + sprintf(sptr, "%u", (uint32_t) algoList[j]); + sptr++; + } + *sptr = '\0'; +} + +static __thread uint32_t s_ntime = 0; +static char hashOrder[HASH_FUNC_COUNT + 1] = { 0 }; +static int s_sequence = -1; + +#define INITIAL_DATE 0x57254700 +static inline int getCurrentAlgoSeq(uint32_t current_time) +{ + // change once per day + return (int) (current_time - INITIAL_DATE) / (60 * 60 * 24); +} + +static void evo_twisted_code(uint32_t ntime, char *permstr) +{ + int seq = getCurrentAlgoSeq(ntime); + if (s_sequence != seq) { + getAlgoString(permstr, seq); + s_sequence = seq; + } +} + +void x11evo_hash(void *output, const void *input) +{ + uint32_t hash[64/4]; + uint32_t len = 80; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + + if (s_sequence == -1) { + uint32_t *data = (uint32_t*) input; + const uint32_t ntime = data[17]; + evo_twisted_code(ntime, hashOrder); + } + + void *in = (void*) input; + int size = len; + + const int hashes = (int) strlen(hashOrder); + + for (int i = 0; i < hashes; i++) + { + const char elem = hashOrder[i]; + uint8_t algo = elem >= 'A' ? elem - 'A' + 10 : elem - '0'; + + if (i > 0) { + in = (void*) hash; + size = 64; + } + + switch (algo) { + case BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512 (&ctx_blake, in, size); + sph_blake512_close (&ctx_blake, hash); + break; + case BMW: + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, in, size); + sph_bmw512_close(&ctx_bmw, hash); + break; + case GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, in, size); + sph_groestl512_close(&ctx_groestl, hash); + break; + case SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512 (&ctx_skein, in, size); + sph_skein512_close (&ctx_skein, hash); + break; + case JH: + sph_jh512_init(&ctx_jh); + sph_jh512 (&ctx_jh, in, size); + sph_jh512_close(&ctx_jh, hash); + break; + case KECCAK: + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, in, size); + sph_keccak512_close(&ctx_keccak, hash); + break; + case LUFFA: + sph_luffa512_init (&ctx_luffa1); + sph_luffa512 (&ctx_luffa1, in, size); + sph_luffa512_close (&ctx_luffa1, hash); + break; + case CUBEHASH: + sph_cubehash512_init (&ctx_cubehash1); + sph_cubehash512 (&ctx_cubehash1, in, size); + sph_cubehash512_close(&ctx_cubehash1, hash); + break; + case SHAVITE: + sph_shavite512_init (&ctx_shavite1); + sph_shavite512 (&ctx_shavite1, in, size); + sph_shavite512_close(&ctx_shavite1, hash); + break; + case SIMD: + sph_simd512_init (&ctx_simd1); + sph_simd512 (&ctx_simd1, in, size); + sph_simd512_close(&ctx_simd1, hash); + break; + case ECHO: + sph_echo512_init (&ctx_echo1); + sph_echo512 (&ctx_echo1, in, size); + sph_echo512_close(&ctx_echo1, hash); + break; + } + } + + memcpy(output, hash, 32); +} + +int scanhash_x11evo(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (s_ntime != pdata[17] || s_sequence == -1) { + uint32_t ntime = swab32(pdata[17]); + evo_twisted_code(ntime, hashOrder); + s_ntime = ntime; + if (opt_debug) applog(LOG_DEBUG, "evo hash order %s (%08x)", hashOrder, ntime); + } + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + x11evo_hash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x12.c b/algo/x12.c new file mode 100644 index 000000000..5cc4cfdde --- /dev/null +++ b/algo/x12.c @@ -0,0 +1,124 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void x12hash(void *output, const void *input) +{ + uint32_t _ALIGN(64) hash[16]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_hamsi512_context ctx_hamsi; + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + memcpy(output, hash, 32); +} + +int scanhash_x12(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + x12hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/x13.c b/algo/x13.c similarity index 84% rename from x13.c rename to algo/x13.c index 61e13bc49..2bfd3f54b 100644 --- a/x13.c +++ b/algo/x13.c @@ -19,13 +19,11 @@ #include "sha3/sph_hamsi.h" #include "sha3/sph_fugue.h" -static void x13hash(void *output, const void *input) +void x13hash(void *output, const void *input) { unsigned char hash[128]; // uint32_t hashA[16], hashB[16]; #define hashB hash+64 - memset(hash, 0, 128); - sph_blake512_context ctx_blake; sph_bmw512_context ctx_bmw; sph_groestl512_context ctx_groestl; @@ -95,16 +93,17 @@ static void x13hash(void *output, const void *input) memcpy(output, hash, 32); } -int scanhash_x13(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) +int scanhash_x13(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) { - uint32_t n = pdata[19] - 1; + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - + uint32_t n = pdata[19] - 1; uint64_t htmax[] = { 0, @@ -124,29 +123,31 @@ int scanhash_x13(int thr_id, uint32_t *pdata, const uint32_t *ptarget, }; // we need bigendian data... - for (int kk=0; kk < 32; kk++) { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + #ifdef DEBUG_ALGO printf("[%d] Htarg=%X\n", thr_id, Htarg); #endif - for (int m=0; m < sizeof(masks); m++) { + for (int m=0; m < 6; m++) { if (Htarg <= htmax[m]) { uint32_t mask = masks[m]; do { pdata[19] = ++n; be32enc(&endiandata[19], n); - x13hash(hash64, &endiandata); + x13hash(hash32, endiandata); #ifndef DEBUG_ALGO - if ((!(hash64[7] & mask)) && fulltest(hash64, ptarget)) { + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; return true; } #else if (!(n % 0x1000) && !thr_id) printf("."); - if (!(hash64[7] & mask)) { + if (!(hash32[7] & mask)) { printf("[%d]",thr_id); - if (fulltest(hash64, ptarget)) { + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; return true; } diff --git a/x14.c b/algo/x14.c similarity index 85% rename from x14.c rename to algo/x14.c index 9fed9c839..c5af12ef4 100644 --- a/x14.c +++ b/algo/x14.c @@ -22,13 +22,11 @@ //#define DEBUG_ALGO -static void x14hash(void *output, const void *input) +void x14hash(void *output, const void *input) { unsigned char hash[128]; // uint32_t hashA[16], hashB[16]; #define hashB hash+64 - memset(hash, 0, 128); - sph_blake512_context ctx_blake; sph_bmw512_context ctx_bmw; sph_groestl512_context ctx_groestl; @@ -103,16 +101,17 @@ static void x14hash(void *output, const void *input) memcpy(output, hash, 32); } -int scanhash_x14(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) +int scanhash_x14(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) { + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + uint32_t n = pdata[19] - 1; const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - uint64_t htmax[] = { 0, 0xF, @@ -131,30 +130,32 @@ int scanhash_x14(int thr_id, uint32_t *pdata, const uint32_t *ptarget, }; // we need bigendian data... - for (int kk=0; kk < 32; kk++) { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + #ifdef DEBUG_ALGO if (Htarg != 0) printf("[%d] Htarg=%X\n", thr_id, Htarg); #endif - for (int m=0; m < sizeof(masks); m++) { + for (int m=0; m < 6; m++) { if (Htarg <= htmax[m]) { uint32_t mask = masks[m]; do { pdata[19] = ++n; be32enc(&endiandata[19], n); - x14hash(hash64, &endiandata); + x14hash(hash32, endiandata); #ifndef DEBUG_ALGO - if ((!(hash64[7] & mask)) && fulltest(hash64, ptarget)) { + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; return true; } #else if (!(n % 0x1000) && !thr_id) printf("."); - if (!(hash64[7] & mask)) { + if (!(hash32[7] & mask)) { printf("[%d]",thr_id); - if (fulltest(hash64, ptarget)) { + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; return true; } diff --git a/x15.c b/algo/x15.c similarity index 85% rename from x15.c rename to algo/x15.c index 51dbbc1ef..41f902af3 100644 --- a/x15.c +++ b/algo/x15.c @@ -23,13 +23,11 @@ //#define DEBUG_ALGO -static void x15hash(void *output, const void *input) +void x15hash(void *output, const void *input) { unsigned char hash[128]; // uint32_t hashA[16], hashB[16]; #define hashB hash+64 - memset(hash, 0, 128); - sph_blake512_context ctx_blake; sph_bmw512_context ctx_bmw; sph_groestl512_context ctx_groestl; @@ -109,16 +107,17 @@ static void x15hash(void *output, const void *input) memcpy(output, hash, 32); } -int scanhash_x15(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) +int scanhash_x15(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) { + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + uint32_t n = pdata[19] - 1; const uint32_t first_nonce = pdata[19]; const uint32_t Htarg = ptarget[7]; - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - uint64_t htmax[] = { 0, 0xF, @@ -137,32 +136,34 @@ int scanhash_x15(int thr_id, uint32_t *pdata, const uint32_t *ptarget, }; // we need bigendian data... - for (int kk=0; kk < 32; kk++) { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + #ifdef DEBUG_ALGO if (Htarg != 0) printf("[%d] Htarg=%X\n", thr_id, Htarg); #endif - for (int m=0; m < sizeof(masks); m++) { + for (int m=0; m < 6; m++) { if (Htarg <= htmax[m]) { uint32_t mask = masks[m]; do { pdata[19] = ++n; be32enc(&endiandata[19], n); - x15hash(hash64, &endiandata); + x15hash(hash32, endiandata); #ifndef DEBUG_ALGO - if ((!(hash64[7] & mask)) && fulltest(hash64, ptarget)) { + if ((!(hash32[7] & mask)) && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; - return true; + return 1; } #else if (!(n % 0x1000) && !thr_id) printf("."); - if (!(hash64[7] & mask)) { + if (!(hash32[7] & mask)) { printf("[%d]",thr_id); - if (fulltest(hash64, ptarget)) { + if (fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); *hashes_done = n - first_nonce + 1; - return true; + return 1; } } #endif diff --git a/algo/x16r.c b/algo/x16r.c new file mode 100644 index 000000000..f6f36084a --- /dev/null +++ b/algo/x16r.c @@ -0,0 +1,230 @@ +/** + * x16r algo implementation + * + * Implementation by tpruvot@github Jan 2018 + */ +#include "miner.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum Algo { + BLAKE = 0, + BMW, + GROESTL, + JH, + KECCAK, + SKEIN, + LUFFA, + CUBEHASH, + SHAVITE, + SIMD, + ECHO, + HAMSI, + FUGUE, + SHABAL, + WHIRLPOOL, + SHA512, + HASH_FUNC_COUNT +}; + +static __thread uint32_t s_ntime = UINT32_MAX; +static __thread char hashOrder[HASH_FUNC_COUNT + 1] = { 0 }; + +static void getAlgoString(const uint8_t* prevblock, char *output) +{ + char *sptr = output; + for (int j = 0; j < HASH_FUNC_COUNT; j++) { + uint8_t b = (15 - j) >> 1; // 16 first ascii hex chars (lsb in uint256) + uint8_t algoDigit = (j & 1) ? prevblock[b] & 0xF : prevblock[b] >> 4; + if (algoDigit >= 10) + sprintf(sptr, "%c", 'A' + (algoDigit - 10)); + else + sprintf(sptr, "%u", (uint32_t) algoDigit); + sptr++; + } + *sptr = '\0'; +} + +void x16r_hash(void* output, const void* input) +{ + uint32_t _ALIGN(128) hash[64/4]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + sph_hamsi512_context ctx_hamsi1; + sph_fugue512_context ctx_fugue1; + sph_shabal512_context ctx_shabal1; + sph_whirlpool_context ctx_whirlpool1; + sph_sha512_context ctx_sha512; + + void *in = (void*) input; + int size = 80; + + if (s_ntime == UINT32_MAX) { + const uint8_t* in8 = (uint8_t*) input; + getAlgoString(&in8[4], hashOrder); + } + + for (int i = 0; i < 16; i++) + { + const char elem = hashOrder[i]; + const uint8_t algo = elem >= 'A' ? elem - 'A' + 10 : elem - '0'; + + switch (algo) { + case BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, in, size); + sph_blake512_close(&ctx_blake, hash); + break; + case BMW: + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, in, size); + sph_bmw512_close(&ctx_bmw, hash); + break; + case GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, in, size); + sph_groestl512_close(&ctx_groestl, hash); + break; + case SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, in, size); + sph_skein512_close(&ctx_skein, hash); + break; + case JH: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, in, size); + sph_jh512_close(&ctx_jh, hash); + break; + case KECCAK: + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, in, size); + sph_keccak512_close(&ctx_keccak, hash); + break; + case LUFFA: + sph_luffa512_init(&ctx_luffa1); + sph_luffa512(&ctx_luffa1, in, size); + sph_luffa512_close(&ctx_luffa1, hash); + break; + case CUBEHASH: + sph_cubehash512_init(&ctx_cubehash1); + sph_cubehash512(&ctx_cubehash1, in, size); + sph_cubehash512_close(&ctx_cubehash1, hash); + break; + case SHAVITE: + sph_shavite512_init(&ctx_shavite1); + sph_shavite512(&ctx_shavite1, in, size); + sph_shavite512_close(&ctx_shavite1, hash); + break; + case SIMD: + sph_simd512_init(&ctx_simd1); + sph_simd512(&ctx_simd1, in, size); + sph_simd512_close(&ctx_simd1, hash); + break; + case ECHO: + sph_echo512_init(&ctx_echo1); + sph_echo512(&ctx_echo1, in, size); + sph_echo512_close(&ctx_echo1, hash); + break; + case HAMSI: + sph_hamsi512_init(&ctx_hamsi1); + sph_hamsi512(&ctx_hamsi1, in, size); + sph_hamsi512_close(&ctx_hamsi1, hash); + break; + case FUGUE: + sph_fugue512_init(&ctx_fugue1); + sph_fugue512(&ctx_fugue1, in, size); + sph_fugue512_close(&ctx_fugue1, hash); + break; + case SHABAL: + sph_shabal512_init(&ctx_shabal1); + sph_shabal512(&ctx_shabal1, in, size); + sph_shabal512_close(&ctx_shabal1, hash); + break; + case WHIRLPOOL: + sph_whirlpool_init(&ctx_whirlpool1); + sph_whirlpool(&ctx_whirlpool1, in, size); + sph_whirlpool_close(&ctx_whirlpool1, hash); + break; + case SHA512: + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) in, size); + sph_sha512_close(&ctx_sha512,(void*) hash); + break; + } + in = (void*) hash; + size = 64; + } + memcpy(output, hash, 32); +} + +int scanhash_x16r(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + if (s_ntime != pdata[17]) { + uint32_t ntime = swab32(pdata[17]); + getAlgoString((const char*) (&endiandata[1]), hashOrder); + s_ntime = ntime; + if (opt_debug && !thr_id) applog(LOG_DEBUG, "hash order %s (%08x)", hashOrder, ntime); + } + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + do { + be32enc(&endiandata[19], nonce); + x16r_hash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x16rv2.c b/algo/x16rv2.c new file mode 100644 index 000000000..989b39688 --- /dev/null +++ b/algo/x16rv2.c @@ -0,0 +1,252 @@ +/** + * x16rv2 algo implementation + * + * Implementation by jsheng08@github Sept 2019 + */ +#include "miner.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum Algo { + BLAKE = 0, + BMW, + GROESTL, + JH, + KECCAK, + SKEIN, + LUFFA, + CUBEHASH, + SHAVITE, + SIMD, + ECHO, + HAMSI, + FUGUE, + SHABAL, + WHIRLPOOL, + SHA512, + HASH_FUNC_COUNT +}; + +static __thread uint32_t s_ntime = UINT32_MAX; +static __thread char hashOrder[HASH_FUNC_COUNT + 1] = { 0 }; + +static void getAlgoString(const uint8_t* prevblock, char *output) +{ + char *sptr = output; + for (int j = 0; j < HASH_FUNC_COUNT; j++) { + uint8_t b = (15 - j) >> 1; // 16 first ascii hex chars (lsb in uint256) + uint8_t algoDigit = (j & 1) ? prevblock[b] & 0xF : prevblock[b] >> 4; + if (algoDigit >= 10) + sprintf(sptr, "%c", 'A' + (algoDigit - 10)); + else + sprintf(sptr, "%u", (uint32_t) algoDigit); + sptr++; + } + *sptr = '\0'; +} + +// Pad the 24 bytes tiger hash to 64 bytes +inline void padtiger512(uint32_t* hash) { + for (int i = (24/4); i < (64/4); i++) hash[i] = 0; +} + +void x16rv2_hash(void* output, const void* input) +{ + uint32_t _ALIGN(128) hash[64/4]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + sph_hamsi512_context ctx_hamsi1; + sph_fugue512_context ctx_fugue1; + sph_shabal512_context ctx_shabal1; + sph_whirlpool_context ctx_whirlpool1; + sph_sha512_context ctx_sha512; + sph_tiger_context ctx_tiger; + + void *in = (void*) input; + int size = 80; + + if (s_ntime == UINT32_MAX) { + const uint8_t* in8 = (uint8_t*) input; + getAlgoString(&in8[4], hashOrder); + } + + for (int i = 0; i < 16; i++) + { + const char elem = hashOrder[i]; + const uint8_t algo = elem >= 'A' ? elem - 'A' + 10 : elem - '0'; + + switch (algo) { + case BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, in, size); + sph_blake512_close(&ctx_blake, hash); + break; + case BMW: + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, in, size); + sph_bmw512_close(&ctx_bmw, hash); + break; + case GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, in, size); + sph_groestl512_close(&ctx_groestl, hash); + break; + case SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, in, size); + sph_skein512_close(&ctx_skein, hash); + break; + case JH: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, in, size); + sph_jh512_close(&ctx_jh, hash); + break; + case KECCAK: + sph_tiger_init(&ctx_tiger); + sph_tiger(&ctx_tiger, in, size); + sph_tiger_close(&ctx_tiger, hash); + padtiger512(hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + break; + case LUFFA: + sph_tiger_init(&ctx_tiger); + sph_tiger(&ctx_tiger, in, size); + sph_tiger_close(&ctx_tiger, hash); + padtiger512(hash); + + sph_luffa512_init(&ctx_luffa1); + sph_luffa512(&ctx_luffa1, hash, 64); + sph_luffa512_close(&ctx_luffa1, hash); + break; + case CUBEHASH: + sph_cubehash512_init(&ctx_cubehash1); + sph_cubehash512(&ctx_cubehash1, in, size); + sph_cubehash512_close(&ctx_cubehash1, hash); + break; + case SHAVITE: + sph_shavite512_init(&ctx_shavite1); + sph_shavite512(&ctx_shavite1, in, size); + sph_shavite512_close(&ctx_shavite1, hash); + break; + case SIMD: + sph_simd512_init(&ctx_simd1); + sph_simd512(&ctx_simd1, in, size); + sph_simd512_close(&ctx_simd1, hash); + break; + case ECHO: + sph_echo512_init(&ctx_echo1); + sph_echo512(&ctx_echo1, in, size); + sph_echo512_close(&ctx_echo1, hash); + break; + case HAMSI: + sph_hamsi512_init(&ctx_hamsi1); + sph_hamsi512(&ctx_hamsi1, in, size); + sph_hamsi512_close(&ctx_hamsi1, hash); + break; + case FUGUE: + sph_fugue512_init(&ctx_fugue1); + sph_fugue512(&ctx_fugue1, in, size); + sph_fugue512_close(&ctx_fugue1, hash); + break; + case SHABAL: + sph_shabal512_init(&ctx_shabal1); + sph_shabal512(&ctx_shabal1, in, size); + sph_shabal512_close(&ctx_shabal1, hash); + break; + case WHIRLPOOL: + sph_whirlpool_init(&ctx_whirlpool1); + sph_whirlpool(&ctx_whirlpool1, in, size); + sph_whirlpool_close(&ctx_whirlpool1, hash); + break; + case SHA512: + sph_tiger_init(&ctx_tiger); + sph_tiger(&ctx_tiger, in, size); + sph_tiger_close(&ctx_tiger, hash); + padtiger512(hash); + + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) hash, 64); + sph_sha512_close(&ctx_sha512,(void*) hash); + break; + } + in = (void*) hash; + size = 64; + } + memcpy(output, hash, 32); +} + +int scanhash_x16rv2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + if (s_ntime != pdata[17]) { + uint32_t ntime = swab32(pdata[17]); + getAlgoString((const char*) (&endiandata[1]), hashOrder); + s_ntime = ntime; + if (opt_debug && !thr_id) applog(LOG_DEBUG, "hash order %s (%08x)", hashOrder, ntime); + } + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + do { + be32enc(&endiandata[19], nonce); + x16rv2_hash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x16s.c b/algo/x16s.c new file mode 100644 index 000000000..b934a1fb2 --- /dev/null +++ b/algo/x16s.c @@ -0,0 +1,235 @@ +/** + * x16s algo implementation + * + * Implementation by tpruvot@github Jan 2018 + */ +#include "miner.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum Algo { + BLAKE = 0, + BMW, + GROESTL, + JH, + KECCAK, + SKEIN, + LUFFA, + CUBEHASH, + SHAVITE, + SIMD, + ECHO, + HAMSI, + FUGUE, + SHABAL, + WHIRLPOOL, + SHA512, + HASH_FUNC_COUNT +}; + +static __thread uint32_t s_ntime = UINT32_MAX; +static __thread char hashOrder[HASH_FUNC_COUNT + 1] = { 0 }; + + +static void getAlgoString(const uint8_t* prevblock, char *output) +{ + uint8_t* data = (uint8_t*)prevblock; + + strcpy(output, "0123456789ABCDEF"); + + for(int i = 0; i < 16; i++){ + uint8_t b = (15 - i) >> 1; // 16 ascii hex chars, reversed + uint8_t algoDigit = (i & 1) ? data[b] & 0xF : data[b] >> 4; + int offset = algoDigit; + // insert the nth character at the front + char oldVal = output[offset]; + for(int j=offset; j-->0;){ + output[j+1] = output[j]; + } + output[0] = oldVal; + } +} + +void x16s_hash(void* output, const void* input) +{ + uint32_t _ALIGN(128) hash[64/4]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + sph_hamsi512_context ctx_hamsi1; + sph_fugue512_context ctx_fugue1; + sph_shabal512_context ctx_shabal1; + sph_whirlpool_context ctx_whirlpool1; + sph_sha512_context ctx_sha512; + + void *in = (void*) input; + int size = 80; + + if (s_ntime == UINT32_MAX) { + const uint8_t* in8 = (uint8_t*) input; + getAlgoString(&in8[4], hashOrder); + } + + for (int i = 0; i < 16; i++) + { + const char elem = hashOrder[i]; + const uint8_t algo = elem >= 'A' ? elem - 'A' + 10 : elem - '0'; + + switch (algo) { + case BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, in, size); + sph_blake512_close(&ctx_blake, hash); + break; + case BMW: + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, in, size); + sph_bmw512_close(&ctx_bmw, hash); + break; + case GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, in, size); + sph_groestl512_close(&ctx_groestl, hash); + break; + case SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, in, size); + sph_skein512_close(&ctx_skein, hash); + break; + case JH: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, in, size); + sph_jh512_close(&ctx_jh, hash); + break; + case KECCAK: + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, in, size); + sph_keccak512_close(&ctx_keccak, hash); + break; + case LUFFA: + sph_luffa512_init(&ctx_luffa1); + sph_luffa512(&ctx_luffa1, in, size); + sph_luffa512_close(&ctx_luffa1, hash); + break; + case CUBEHASH: + sph_cubehash512_init(&ctx_cubehash1); + sph_cubehash512(&ctx_cubehash1, in, size); + sph_cubehash512_close(&ctx_cubehash1, hash); + break; + case SHAVITE: + sph_shavite512_init(&ctx_shavite1); + sph_shavite512(&ctx_shavite1, in, size); + sph_shavite512_close(&ctx_shavite1, hash); + break; + case SIMD: + sph_simd512_init(&ctx_simd1); + sph_simd512(&ctx_simd1, in, size); + sph_simd512_close(&ctx_simd1, hash); + break; + case ECHO: + sph_echo512_init(&ctx_echo1); + sph_echo512(&ctx_echo1, in, size); + sph_echo512_close(&ctx_echo1, hash); + break; + case HAMSI: + sph_hamsi512_init(&ctx_hamsi1); + sph_hamsi512(&ctx_hamsi1, in, size); + sph_hamsi512_close(&ctx_hamsi1, hash); + break; + case FUGUE: + sph_fugue512_init(&ctx_fugue1); + sph_fugue512(&ctx_fugue1, in, size); + sph_fugue512_close(&ctx_fugue1, hash); + break; + case SHABAL: + sph_shabal512_init(&ctx_shabal1); + sph_shabal512(&ctx_shabal1, in, size); + sph_shabal512_close(&ctx_shabal1, hash); + break; + case WHIRLPOOL: + sph_whirlpool_init(&ctx_whirlpool1); + sph_whirlpool(&ctx_whirlpool1, in, size); + sph_whirlpool_close(&ctx_whirlpool1, hash); + break; + case SHA512: + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) in, size); + sph_sha512_close(&ctx_sha512,(void*) hash); + break; + } + in = (void*) hash; + size = 64; + } + memcpy(output, hash, 32); +} + +int scanhash_x16s(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + if (s_ntime != pdata[17]) { + uint32_t ntime = swab32(pdata[17]); + getAlgoString((const uint8_t*) (&endiandata[1]), hashOrder); + s_ntime = ntime; + if (opt_debug && !thr_id) applog(LOG_DEBUG, "hash order %s (%08x)", hashOrder, ntime); + } + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + do { + be32enc(&endiandata[19], nonce); + x16s_hash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x17.c b/algo/x17.c new file mode 100644 index 000000000..4aff41cba --- /dev/null +++ b/algo/x17.c @@ -0,0 +1,156 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG_ALGO + +void x17hash(void *output, const void *input) +{ + unsigned char _ALIGN(64) hash[64]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + sph_shabal512_context ctx_shabal; + sph_whirlpool_context ctx_whirlpool; + sph_sha512_context ctx_sha512; + sph_haval256_5_context ctx_haval; + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, 64); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, 64); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hash, 64); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hash, 64); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hash, 64); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hash, 64); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, hash, 64); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, hash, 64); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, 64); + sph_shabal512_close(&ctx_shabal, hash); + + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, hash, 64); + sph_whirlpool_close(&ctx_whirlpool, hash); + + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) hash, 64); + sph_sha512_close(&ctx_sha512,(void*) hash); + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval,(const void*) hash, 64); + sph_haval256_5_close(&ctx_haval, hash); + + memcpy(output, hash, 32); +} + +int scanhash_x17(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + x17hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/x20r.c b/algo/x20r.c new file mode 100644 index 000000000..12f6b099b --- /dev/null +++ b/algo/x20r.c @@ -0,0 +1,261 @@ +#include "miner.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum Algo { + BLAKE = 0, + BMW, + GROESTL, + JH, + KECCAK, + SKEIN, + LUFFA, + CUBEHASH, + SHAVITE, + SIMD, + ECHO, + HAMSI, + FUGUE, + SHABAL, + WHIRLPOOL, + SHA512, + HAVAL, // 256-bits output + GOST, + RADIOGATUN, // 256-bits output + PANAMA, // 256-bits output + HASH_FUNC_COUNT +}; + +static __thread uint32_t s_ntime = UINT32_MAX; +static __thread char hashOrder[HASH_FUNC_COUNT + 1] = { 0 }; + +static void getAlgoString(const uint8_t* prevblock, char *output) +{ + char *sptr = output; + + for (int j = 0; j < HASH_FUNC_COUNT; j++) { + char b = (19 - j) >> 1; // 16 ascii hex chars, reversed + uint8_t algoDigit = (j & 1) ? prevblock[b] & 0xF : prevblock[b] >> 4; + if (algoDigit >= 10) + sprintf(sptr, "%c", 'A' + (algoDigit - 10)); + else + sprintf(sptr, "%u", (uint32_t) algoDigit); + sptr++; + } + *sptr = '\0'; +} + +void x20r_hash(void* output, const void* input) +{ + uint32_t _ALIGN(128) hash[64/4]; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + sph_shabal512_context ctx_shabal; + sph_whirlpool_context ctx_whirlpool; + sph_sha512_context ctx_sha512; + sph_haval256_5_context ctx_haval; + sph_gost512_context ctx_gost; + sph_radiogatun64_context ctx_radiogatun; + sph_panama_context ctx_panama; + + void *in = (void*) input; + int size = 80; + + if (s_ntime == UINT32_MAX) { + const uint8_t* in8 = (uint8_t*) input; + getAlgoString(&in8[4], hashOrder); + } + + for (int i = 0; i < 20; i++) + { + const char elem = hashOrder[i]; + const uint8_t algo = elem >= 'A' ? elem - 'A' + 10 : elem - '0'; + + switch (algo) { + case BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, in, size); + sph_blake512_close(&ctx_blake, hash); + break; + case BMW: + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, in, size); + sph_bmw512_close(&ctx_bmw, hash); + break; + case GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, in, size); + sph_groestl512_close(&ctx_groestl, hash); + break; + case SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, in, size); + sph_skein512_close(&ctx_skein, hash); + break; + case JH: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, in, size); + sph_jh512_close(&ctx_jh, hash); + break; + case KECCAK: + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, in, size); + sph_keccak512_close(&ctx_keccak, hash); + break; + case LUFFA: + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, in, size); + sph_luffa512_close(&ctx_luffa, hash); + break; + case CUBEHASH: + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, in, size); + sph_cubehash512_close(&ctx_cubehash, hash); + break; + case SHAVITE: + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, in, size); + sph_shavite512_close(&ctx_shavite, hash); + break; + case SIMD: + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, in, size); + sph_simd512_close(&ctx_simd, hash); + break; + case ECHO: + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, in, size); + sph_echo512_close(&ctx_echo, hash); + break; + case HAMSI: + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, in, size); + sph_hamsi512_close(&ctx_hamsi, hash); + break; + case FUGUE: + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, in, size); + sph_fugue512_close(&ctx_fugue, hash); + break; + case SHABAL: + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, in, size); + sph_shabal512_close(&ctx_shabal, hash); + break; + case WHIRLPOOL: + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, in, size); + sph_whirlpool_close(&ctx_whirlpool, hash); + break; + case SHA512: + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) in, size); + sph_sha512_close(&ctx_sha512,(void*) hash); + break; + case HAVAL: + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval, in, size); + sph_haval256_5_close(&ctx_haval, hash); + memset(&hash[8], 0, 32); + break; + case GOST: + sph_gost512_init(&ctx_gost); + sph_gost512(&ctx_gost, in, size); + sph_gost512_close(&ctx_gost, hash); + break; + case RADIOGATUN: + sph_radiogatun64_init(&ctx_radiogatun); + sph_radiogatun64(&ctx_radiogatun, in, size); + sph_radiogatun64_close(&ctx_radiogatun, hash); + memset(&hash[8], 0, 32); + break; + case PANAMA: + sph_panama_init(&ctx_panama); + sph_panama(&ctx_panama, in, size); + sph_panama_close(&ctx_panama, hash); + memset(&hash[8], 0, 32); + break; + } + in = (void*) hash; + size = 64; + } + memcpy(output, hash, 32); +} + +int scanhash_x20r(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(128) hash32[8]; + uint32_t _ALIGN(128) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + if (s_ntime != pdata[17]) { + uint32_t ntime = swab32(pdata[17]); + getAlgoString((const char*) (&endiandata[1]), hashOrder); + s_ntime = ntime; + if (opt_debug && !thr_id) applog(LOG_DEBUG, "hash order %s (%08x)", hashOrder, ntime); + } + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + do { + be32enc(&endiandata[19], nonce); + x20r_hash(hash32, endiandata); + + if (hash32[7] <= Htarg && fulltest(hash32, ptarget)) { + work_set_target_ratio(work, hash32); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/xevan.c b/algo/xevan.c new file mode 100644 index 000000000..514beff64 --- /dev/null +++ b/algo/xevan.c @@ -0,0 +1,227 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void xevan_hash(void *output, const void *input) +{ + uint32_t _ALIGN(64) hash[32]; // 128 bytes required + const int dataLen = 128; + + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + sph_shabal512_context ctx_shabal; + sph_whirlpool_context ctx_whirlpool; + sph_sha512_context ctx_sha512; + sph_haval256_5_context ctx_haval; + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, input, 80); + sph_blake512_close(&ctx_blake, hash); + + memset(&hash[16], 0, 64); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hash, dataLen); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hash, dataLen); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, dataLen); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hash, dataLen); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hash, dataLen); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, dataLen); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hash, dataLen); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hash, dataLen); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hash, dataLen); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hash, dataLen); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, hash, dataLen); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, hash, dataLen); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, dataLen); + sph_shabal512_close(&ctx_shabal, hash); + + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, hash, dataLen); + sph_whirlpool_close(&ctx_whirlpool, hash); + + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) hash, dataLen); + sph_sha512_close(&ctx_sha512,(void*) hash); + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval,(const void*) hash, dataLen); + sph_haval256_5_close(&ctx_haval, hash); + + memset(&hash[8], 0, dataLen - 32); + + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, hash, dataLen); + sph_blake512_close(&ctx_blake, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512(&ctx_bmw, hash, dataLen); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, hash, dataLen); + sph_groestl512_close(&ctx_groestl, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, hash, dataLen); + sph_skein512_close(&ctx_skein, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, hash, dataLen); + sph_jh512_close(&ctx_jh, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, hash, dataLen); + sph_keccak512_close(&ctx_keccak, hash); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512(&ctx_luffa, hash, dataLen); + sph_luffa512_close(&ctx_luffa, hash); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512(&ctx_cubehash, hash, dataLen); + sph_cubehash512_close(&ctx_cubehash, hash); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, hash, dataLen); + sph_shavite512_close(&ctx_shavite, hash); + + sph_simd512_init(&ctx_simd); + sph_simd512(&ctx_simd, hash, dataLen); + sph_simd512_close(&ctx_simd, hash); + + sph_echo512_init(&ctx_echo); + sph_echo512(&ctx_echo, hash, dataLen); + sph_echo512_close(&ctx_echo, hash); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512(&ctx_hamsi, hash, dataLen); + sph_hamsi512_close(&ctx_hamsi, hash); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512(&ctx_fugue, hash, dataLen); + sph_fugue512_close(&ctx_fugue, hash); + + sph_shabal512_init(&ctx_shabal); + sph_shabal512(&ctx_shabal, hash, dataLen); + sph_shabal512_close(&ctx_shabal, hash); + + sph_whirlpool_init(&ctx_whirlpool); + sph_whirlpool(&ctx_whirlpool, hash, dataLen); + sph_whirlpool_close(&ctx_whirlpool, hash); + + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512,(const void*) hash, dataLen); + sph_sha512_close(&ctx_sha512,(void*) hash); + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval,(const void*) hash, dataLen); + sph_haval256_5_close(&ctx_haval, hash); + + memcpy(output, hash, 32); +} + +int scanhash_xevan(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + volatile uint8_t *restart = &(work_restart[thr_id].restart); + + if (opt_benchmark) + ptarget[7] = 0x0cff; + + for (int k=0; k < 19; k++) + be32enc(&endiandata[k], pdata[k]); + + do { + be32enc(&endiandata[19], nonce); + xevan_hash(hash, endiandata); + + if (hash[7] <= Htarg && fulltest(hash, ptarget)) { + work_set_target_ratio(work, hash); + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !(*restart)); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/algo/yescrypt.c b/algo/yescrypt.c new file mode 100644 index 000000000..056abfc9f --- /dev/null +++ b/algo/yescrypt.c @@ -0,0 +1,64 @@ +#include "miner.h" + +#include +#include +#include +#include +#include + +#include "yescrypt/yescrypt.h" + +int do_scanhash(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, void (*hash_func)(const char *, char *, uint32_t)) +{ + uint32_t _ALIGN(64) vhash[8]; + uint32_t _ALIGN(64) endiandata[20]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + + const uint32_t Htarg = ptarget[7]; + const uint32_t first_nonce = pdata[19]; + + uint32_t n = first_nonce; + + for (int i=0; i < 19; i++) { + be32enc(&endiandata[i], pdata[i]); + } + + do { + be32enc(&endiandata[19], n); + hash_func((char*) endiandata, (char*) vhash, 80); + if (vhash[7] < Htarg && fulltest(vhash, ptarget)) { + work_set_target_ratio(work, vhash); + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + return true; + } + n++; + + } while (n < max_nonce && !work_restart[thr_id].restart); + + *hashes_done = n - first_nonce + 1; + pdata[19] = n; + + return 0; +} + +int scanhash_yescrypt(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + return (do_scanhash(thr_id, work, max_nonce, hashes_done, yescrypt_hash)); +} + +int scanhash_yescryptr8(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + return (do_scanhash(thr_id, work, max_nonce, hashes_done, yescrypt_hash_r8)); +} + +int scanhash_yescryptr16(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + return (do_scanhash(thr_id, work, max_nonce, hashes_done, yescrypt_hash_r16)); +} + +int scanhash_yescryptr32(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + return (do_scanhash(thr_id, work, max_nonce, hashes_done, yescrypt_hash_r32)); +} diff --git a/algo/zr5.c b/algo/zr5.c new file mode 100644 index 000000000..2098b4dd0 --- /dev/null +++ b/algo/zr5.c @@ -0,0 +1,146 @@ +#include "miner.h" + +#include +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" + +#define ZR_BLAKE 0 +#define ZR_GROESTL 1 +#define ZR_JH512 2 +#define ZR_SKEIN 3 + +#define POK_BOOL_MASK 0x00008000 +#define POK_DATA_MASK 0xFFFF0000 + +static const int permut[24][4] = { + {0, 1, 2, 3}, + {0, 1, 3, 2}, + {0, 2, 1, 3}, + {0, 2, 3, 1}, + {0, 3, 1, 2}, + {0, 3, 2, 1}, + {1, 0, 2, 3}, + {1, 0, 3, 2}, + {1, 2, 0, 3}, + {1, 2, 3, 0}, + {1, 3, 0, 2}, + {1, 3, 2, 0}, + {2, 0, 1, 3}, + {2, 0, 3, 1}, + {2, 1, 0, 3}, + {2, 1, 3, 0}, + {2, 3, 0, 1}, + {2, 3, 1, 0}, + {3, 0, 1, 2}, + {3, 0, 2, 1}, + {3, 1, 0, 2}, + {3, 1, 2, 0}, + {3, 2, 0, 1}, + {3, 2, 1, 0} +}; + +void zr5hash(void *output, const void *input) +{ + sph_keccak512_context ctx_keccak; + sph_blake512_context ctx_blake; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_skein512_context ctx_skein; + + uchar _ALIGN(64) hash[64]; + uint32_t *phash = (uint32_t *) hash; + uint32_t norder; + + sph_keccak512_init(&ctx_keccak); + sph_keccak512(&ctx_keccak, (const void*) input, 80); + sph_keccak512_close(&ctx_keccak, (void*) phash); + + norder = phash[0] % ARRAY_SIZE(permut); /* % 24 */ + + for(int i = 0; i < 4; i++) + { + switch (permut[norder][i]) { + case ZR_BLAKE: + sph_blake512_init(&ctx_blake); + sph_blake512(&ctx_blake, (const void*) phash, 64); + sph_blake512_close(&ctx_blake, phash); + break; + case ZR_GROESTL: + sph_groestl512_init(&ctx_groestl); + sph_groestl512(&ctx_groestl, (const void*) phash, 64); + sph_groestl512_close(&ctx_groestl, phash); + break; + case ZR_JH512: + sph_jh512_init(&ctx_jh); + sph_jh512(&ctx_jh, (const void*) phash, 64); + sph_jh512_close(&ctx_jh, phash); + break; + case ZR_SKEIN: + sph_skein512_init(&ctx_skein); + sph_skein512(&ctx_skein, (const void*) phash, 64); + sph_skein512_close(&ctx_skein, phash); + break; + default: + break; + } + } + memcpy(output, phash, 32); +} + +void zr5hash_pok(void *output, uint32_t *pdata) +{ + const uint32_t version = pdata[0] & (~POK_DATA_MASK); + uint32_t _ALIGN(64) hash[8]; + uint32_t pok; + + pdata[0] = version; + zr5hash(hash, pdata); + + // fill PoK + pok = version | (hash[0] & POK_DATA_MASK); + if (pdata[0] != pok) { + pdata[0] = pok; + zr5hash(hash, pdata); + } + memcpy(output, hash, 32); +} + +int scanhash_zr5(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done) +{ + uint32_t _ALIGN(64) hash[16]; + uint32_t *pdata = work->data; + uint32_t *ptarget = work->target; + const uint32_t first_nonce = pdata[19]; + uint32_t nonce = first_nonce; + #define tmpdata pdata + + if (opt_benchmark) + ptarget[7] = 0x00ff; + + do { + tmpdata[19] = nonce; + zr5hash_pok(hash, tmpdata); + + if (hash[7] <= ptarget[7] && fulltest(hash, ptarget)) + { + work_set_target_ratio(work, hash); + pdata[0] = tmpdata[0]; + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 1; + } + nonce++; + + } while (nonce < max_nonce && !work_restart[thr_id].restart); + + pdata[19] = nonce; + *hashes_done = pdata[19] - first_nonce + 1; + return 0; +} diff --git a/api.c b/api.c new file mode 100644 index 000000000..fd1f08581 --- /dev/null +++ b/api.c @@ -0,0 +1,721 @@ +/* + * Copyright 2014 ccminer team + * + * Implementation by tpruvot (based on cgminer) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. See COPYING for more details. + */ +#define APIVERSION "1.1" + +#ifdef WIN32 +# define _WINSOCK_DEPRECATED_NO_WARNINGS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "miner.h" + +#ifndef WIN32 +# include +# include +# include +# include +# include +# define SOCKETTYPE long +# define SOCKETFAIL(a) ((a) < 0) +# define INVSOCK -1 /* INVALID_SOCKET */ +# define INVINETADDR -1 /* INADDR_NONE */ +# define CLOSESOCKET close +# define SOCKETINIT {} +# define SOCKERRMSG strerror(errno) +#else +# define SOCKETTYPE SOCKET +# define SOCKETFAIL(a) ((a) == SOCKET_ERROR) +# define INVSOCK INVALID_SOCKET +# define INVINETADDR INADDR_NONE +# define CLOSESOCKET closesocket +# define in_addr_t uint32_t +#endif + +#define GROUP(g) (toupper(g)) +#define PRIVGROUP GROUP('W') +#define NOPRIVGROUP GROUP('R') +#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) +#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) +#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) +#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) +#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) +struct APIGROUPS { + // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search + char *commands; +} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) + +struct IP4ACCESS { + in_addr_t ip; + in_addr_t mask; + char group; +}; + +static int ips = 1; +static struct IP4ACCESS *ipaccess = NULL; + +// Socket data buffers +#define MYBUFSIZ 16384 +#define SOCK_REC_BUFSZ 1024 + +// Socket is on 127.0.0.1 +#define QUEUE 10 + +#define ALLIP4 "0.0.0.0" + +static const char *localaddr = "127.0.0.1"; +static const char *UNAVAILABLE = " - API will not be available"; +static char *buffer = NULL; +static time_t startup = 0; +static int bye = 0; + +extern char *opt_api_allow; +extern int opt_api_listen; /* port */ +extern int opt_api_remote; +extern uint64_t global_hashrate; +extern uint32_t solved_count; +extern uint32_t accepted_count; +extern uint32_t rejected_count; + +#define cpu_threads opt_n_threads + +#define USE_MONITORING +extern float cpu_temp(int); +extern uint32_t cpu_clock(int); +extern int cpu_fanpercent(void); + +/***************************************************************/ + +static void cpustatus(int thr_id) +{ + if (thr_id >= 0 && thr_id < opt_n_threads) { + struct cpu_info *cpu = &thr_info[thr_id].cpu; + char buf[512]; *buf = '\0'; + + cpu->thr_id = thr_id; + cpu->khashes = thr_hashrates[thr_id] / 1000.0; //todo: stats_get_speed(thr_id, 0.0) / 1000.0; + + snprintf(buf, sizeof(buf), "CPU=%d;KHS=%.2f|", thr_id, cpu->khashes); + + // append to buffer + strcat(buffer, buf); + } +} + +/*****************************************************************************/ + +/** +* Returns miner global infos +*/ +static char *getsummary(char *params) +{ + char algo[64]; *algo = '\0'; + time_t ts = time(NULL); + double uptime = difftime(ts, startup); + double accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0); + + struct cpu_info cpu = { 0 }; +#ifdef USE_MONITORING + cpu.has_monitoring = true; + cpu.cpu_temp = cpu_temp(0); + cpu.cpu_fan = cpu_fanpercent(); + cpu.cpu_clock = cpu_clock(0); +#endif + + get_currentalgo(algo, sizeof(algo)); + + *buffer = '\0'; + sprintf(buffer, "NAME=%s;VER=%s;API=%s;" + "ALGO=%s;CPUS=%d;KHS=%.2f;SOLV=%d;ACC=%d;REJ=%d;" + "ACCMN=%.3f;DIFF=%.6f;TEMP=%.1f;FAN=%d;FREQ=%d;" + "UPTIME=%.0f;TS=%u|", + PACKAGE_NAME, PACKAGE_VERSION, APIVERSION, + algo, opt_n_threads, (double)global_hashrate / 1000.0, + solved_count, accepted_count, rejected_count, accps, net_diff > 0. ? net_diff : stratum_diff, + cpu.cpu_temp, cpu.cpu_fan, cpu.cpu_clock, + uptime, (uint32_t) ts); + return buffer; +} + +/** + * Returns cpu/thread specific stats + */ +static char *getthreads(char *params) +{ + *buffer = '\0'; + for (int i = 0; i < opt_n_threads; i++) + cpustatus(i); + return buffer; +} + +/** + * Is remote control allowed ? + */ +static bool check_remote_access(void) +{ + return (opt_api_remote > 0); +} + +/** + * Change pool url (see --url parameter) + * seturl|stratum+tcp://XeVrkPrWB7pDbdFLfKhF1Z3xpqhsx6wkH3:X@stratum+tcp://mine.xpool.ca:1131| + * seturl|stratum+tcp://Danila.1:X@pool.ipominer.com:3335| + */ +extern bool stratum_need_reset; +static char *remote_seturl(char *params) +{ + *buffer = '\0'; + if (!check_remote_access()) + return buffer; + parse_arg('o', params); + stratum_need_reset = true; + sprintf(buffer, "%s", "ok|"); + return buffer; +} + +/** + * Ask the miner to quit + */ +static char *remote_quit(char *params) +{ + *buffer = '\0'; + if (!check_remote_access()) + return buffer; + bye = 1; + sprintf(buffer, "%s", "bye|"); + return buffer; +} + +static char *gethelp(char *params); +struct CMDS { + const char *name; + char *(*func)(char *); +} cmds[] = { + { "summary", getsummary }, + { "threads", getthreads }, + /* remote functions */ + { "seturl", remote_seturl }, + { "quit", remote_quit }, + /* keep it the last */ + { "help", gethelp }, +}; +#define CMDMAX ARRAY_SIZE(cmds) + +static char *gethelp(char *params) +{ + *buffer = '\0'; + char * p = buffer; + for (int i = 0; i < CMDMAX-1; i++) + p += sprintf(p, "%s\n", cmds[i].name); + sprintf(p, "|"); + return buffer; +} + + +static int send_result(SOCKETTYPE c, char *result) +{ + int n; + if (!result) { + n = (int) send(c, "", 1, 0); + } else { + // ignore failure - it's closed immediately anyway + n = (int) send(c, result, (int) strlen(result) + 1, 0); + } + return n; +} + +/* ---- Base64 Encoding/Decoding Table --- */ +static const char table64[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static size_t base64_encode(const uchar *indata, size_t insize, char *outptr, size_t outlen) +{ + uchar ibuf[3]; + uchar obuf[4]; + int i, inputparts, inlen = (int) insize; + size_t len = 0; + char *output, *outbuf; + + memset(outptr, 0, outlen); + + outbuf = output = (char*)calloc(1, inlen * 4 / 3 + 4); + if (outbuf == NULL) { + return -1; + } + + while (inlen > 0) { + for (i = inputparts = 0; i < 3; i++) { + if (inlen > 0) { + inputparts++; + ibuf[i] = (uchar) *indata; + indata++; inlen--; + } + else + ibuf[i] = 0; + } + + obuf[0] = (uchar) ((ibuf[0] & 0xFC) >> 2); + obuf[1] = (uchar) (((ibuf[0] & 0x03) << 4) | ((ibuf[1] & 0xF0) >> 4)); + obuf[2] = (uchar) (((ibuf[1] & 0x0F) << 2) | ((ibuf[2] & 0xC0) >> 6)); + obuf[3] = (uchar) (ibuf[2] & 0x3F); + + switch(inputparts) { + case 1: /* only one byte read */ + snprintf(output, 5, "%c%c==", + table64[obuf[0]], + table64[obuf[1]]); + break; + case 2: /* two bytes read */ + snprintf(output, 5, "%c%c%c=", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]]); + break; + default: + snprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]] ); + break; + } + if ((len+4) > outlen) + break; + output += 4; len += 4; + } + len = snprintf(outptr, len, "%s", outbuf); + // todo: seems to be missing on linux + if (strlen(outptr) == 27) + strcat(outptr, "="); + free(outbuf); + + return len; +} + +#include "compat/curl-for-windows/openssl/openssl/crypto/sha/sha.h" + +/* websocket handshake (tested in Chrome) */ +static int websocket_handshake(SOCKETTYPE c, char *result, char *clientkey) +{ + char answer[256]; + char inpkey[128] = { 0 }; + char seckey[64]; + uchar sha1[20]; + SHA_CTX ctx; + + if (opt_protocol) + applog(LOG_DEBUG, "clientkey: %s", clientkey); + + sprintf(inpkey, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", clientkey); + + // SHA-1 test from rfc, returns in base64 "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" + //sprintf(inpkey, "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + + SHA1_Init(&ctx); + SHA1_Update(&ctx, inpkey, strlen(inpkey)); + SHA1_Final(sha1, &ctx); + + base64_encode(sha1, 20, seckey, sizeof(seckey)); + + sprintf(answer, + "HTTP/1.1 101 Switching Protocol\r\n" + "Upgrade: WebSocket\r\nConnection: Upgrade\r\n" + "Sec-WebSocket-Accept: %s\r\n" + "Sec-WebSocket-Protocol: text\r\n" + "\r\n", seckey); + + // data result as tcp frame + + uchar hd[10] = { 0 }; + hd[0] = 129; // 0x1 text frame (FIN + opcode) + uint64_t datalen = (uint64_t) strlen(result); + uint8_t frames = 2; + if (datalen <= 125) { + hd[1] = (uchar) (datalen); + } else if (datalen <= 65535) { + hd[1] = (uchar) 126; + hd[2] = (uchar) (datalen >> 8); + hd[3] = (uchar) (datalen); + frames = 4; + } else { + hd[1] = (uchar) 127; + hd[2] = (uchar) (datalen >> 56); + hd[3] = (uchar) (datalen >> 48); + hd[4] = (uchar) (datalen >> 40); + hd[5] = (uchar) (datalen >> 32); + hd[6] = (uchar) (datalen >> 24); + hd[7] = (uchar) (datalen >> 16); + hd[8] = (uchar) (datalen >> 8); + hd[9] = (uchar) (datalen); + frames = 10; + } + + size_t handlen = strlen(answer); + uchar *data = (uchar*) calloc(1, handlen + frames + (size_t) datalen + 1); + if (data == NULL) + return -1; + else { + uchar *p = data; + // HTTP header 101 + memcpy(p, answer, handlen); + p += handlen; + // WebSocket Frame - Header + Data + memcpy(p, hd, frames); + memcpy(p + frames, result, (size_t)datalen); + send(c, (const char*)data, (int) (strlen(answer) + frames + (size_t)datalen + 1), 0); + free(data); + } + return 0; +} + +/* + * N.B. IP4 addresses are by Definition 32bit big endian on all platforms + */ +static void setup_ipaccess() +{ + char *buf = NULL, *ptr, *comma, *slash, *dot; + int ipcount, mask, octet, i; + char group; + + buf = (char*) calloc(1, strlen(opt_api_allow) + 1); + if (unlikely(!buf)) + proper_exit(1);//, "Failed to malloc ipaccess buf"); + + strcpy(buf, opt_api_allow); + ipcount = 1; + ptr = buf; + while (*ptr) if (*(ptr++) == ',') + ipcount++; + + // possibly more than needed, but never less + ipaccess = (struct IP4ACCESS *) calloc(ipcount, sizeof(struct IP4ACCESS)); + if (unlikely(!ipaccess)) + proper_exit(1);//, "Failed to calloc ipaccess"); + + ips = 0; + ptr = buf; + while (ptr && *ptr) { + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + if (*ptr == ',') { + ptr++; + continue; + } + + comma = strchr(ptr, ','); + if (comma) + *(comma++) = '\0'; + + group = NOPRIVGROUP; + + if (isalpha(*ptr) && *(ptr+1) == ':') { + if (DEFINEDGROUP(*ptr)) + group = GROUP(*ptr); + ptr += 2; + } + + ipaccess[ips].group = group; + + if (strcmp(ptr, ALLIP4) == 0) + ipaccess[ips].ip = ipaccess[ips].mask = 0; + else + { + slash = strchr(ptr, '/'); + if (!slash) + ipaccess[ips].mask = 0xffffffff; + else { + *(slash++) = '\0'; + mask = atoi(slash); + if (mask < 1 || mask > 32) + goto popipo; // skip invalid/zero + + ipaccess[ips].mask = 0; + while (mask-- >= 0) { + octet = 1 << (mask % 8); + ipaccess[ips].mask |= (octet << (24 - (8 * (mask >> 3)))); + } + } + + ipaccess[ips].ip = 0; // missing default to '.0' + for (i = 0; ptr && (i < 4); i++) { + dot = strchr(ptr, '.'); + if (dot) + *(dot++) = '\0'; + octet = atoi(ptr); + + if (octet < 0 || octet > 0xff) + goto popipo; // skip invalid + + ipaccess[ips].ip |= (octet << (24 - (i * 8))); + + ptr = dot; + } + + ipaccess[ips].ip &= ipaccess[ips].mask; + } + + ips++; +popipo: + ptr = comma; + } + + free(buf); +} + +static bool check_connect(struct sockaddr_in *cli, char **connectaddr, char *group) +{ + bool addrok = false; + + *connectaddr = inet_ntoa(cli->sin_addr); + + *group = NOPRIVGROUP; + if (opt_api_allow) { + int client_ip = htonl(cli->sin_addr.s_addr); + for (int i = 0; i < ips; i++) { + if ((client_ip & ipaccess[i].mask) == ipaccess[i].ip) { + addrok = true; + *group = ipaccess[i].group; + break; + } + } + } + else + addrok = (strcmp(*connectaddr, localaddr) == 0); + + return addrok; +} + +static void api() +{ + const char *addr = opt_api_allow; + unsigned short port = (unsigned short) opt_api_listen; // 4048 + char buf[MYBUFSIZ]; + int c, n, bound; + char *connectaddr; + char *binderror; + char group; + time_t bindstart; + struct sockaddr_in serv; + struct sockaddr_in cli; + socklen_t clisiz; + bool addrok = false; + long long counter; + char *result; + char *params; + int i; + + SOCKETTYPE *apisock; + if (!opt_api_listen && opt_debug) { + applog(LOG_DEBUG, "API disabled"); + return; + } + + if (opt_api_allow) { + setup_ipaccess(); + if (ips == 0) { + applog(LOG_WARNING, "API not running (no valid IPs specified)%s", UNAVAILABLE); + } + } + + apisock = (SOCKETTYPE*) calloc(1, sizeof(*apisock)); + *apisock = INVSOCK; + + sleep(1); + + *apisock = socket(AF_INET, SOCK_STREAM, 0); + if (*apisock == INVSOCK) { + applog(LOG_ERR, "API initialisation failed (%s)%s", strerror(errno), UNAVAILABLE); + return; + } + + memset(&serv, 0, sizeof(serv)); + serv.sin_family = AF_INET; + serv.sin_addr.s_addr = inet_addr(addr); + if (serv.sin_addr.s_addr == (in_addr_t)INVINETADDR) { + applog(LOG_ERR, "API initialisation 2 failed (%s)%s", strerror(errno), UNAVAILABLE); + return; + } + + serv.sin_port = htons(port); + +#ifndef WIN32 + // On linux with SO_REUSEADDR, bind will get the port if the previous + // socket is closed (even if it is still in TIME_WAIT) but fail if + // another program has it open - which is what we want + int optval = 1; + // If it doesn't work, we don't really care - just show a debug message + if (SOCKETFAIL(setsockopt(*apisock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) + applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG); +#else + // On windows a 2nd program can bind to a port>1024 already in use unless + // SO_EXCLUSIVEADDRUSE is used - however then the bind to a closed port + // in TIME_WAIT will fail until the timeout - so we leave the options alone +#endif + + // try for 1 minute ... in case the old one hasn't completely gone yet + bound = 0; + bindstart = time(NULL); + while (bound == 0) { + if (bind(*apisock, (struct sockaddr *)(&serv), sizeof(serv)) < 0) { + binderror = strerror(errno); + if ((time(NULL) - bindstart) > 61) + break; + else { + if (!opt_quiet || opt_debug) + applog(LOG_WARNING, "API bind to port %d failed - trying again in 20sec", port); + sleep(20); + } + } + else + bound = 1; + } + + if (bound == 0) { + applog(LOG_WARNING, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE); + free(apisock); + return; + } + + if (SOCKETFAIL(listen(*apisock, QUEUE))) { + applog(LOG_ERR, "API initialisation 3 failed (%s)%s", strerror(errno), UNAVAILABLE); + CLOSESOCKET(*apisock); + free(apisock); + return; + } + + buffer = (char *) calloc(1, MYBUFSIZ + 1); + + counter = 0; + while (bye == 0) { + counter++; + + clisiz = sizeof(cli); + if (SOCKETFAIL(c = accept((SOCKETTYPE)*apisock, (struct sockaddr *)(&cli), &clisiz))) { + applog(LOG_ERR, "API failed (%s)%s", strerror(errno), UNAVAILABLE); + CLOSESOCKET(*apisock); + free(apisock); + free(buffer); + return; + } + + addrok = check_connect(&cli, &connectaddr, &group); + if (opt_debug && opt_protocol) + applog(LOG_DEBUG, "API: connection from %s - %s", + connectaddr, addrok ? "Accepted" : "Ignored"); + + if (addrok) { + bool fail; + char *wskey = NULL; + n = recv(c, &buf[0], SOCK_REC_BUFSZ, 0); + + fail = SOCKETFAIL(n); + if (fail) + buf[0] = '\0'; + else if (n > 0 && buf[n-1] == '\n') { + /* telnet compat \r\n */ + buf[n-1] = '\0'; n--; + if (n > 0 && buf[n-1] == '\r') + buf[n-1] = '\0'; + } + if (n >= 0) + buf[n] = '\0'; + + //if (opt_debug && opt_protocol && n > 0) + // applog(LOG_DEBUG, "API: recv command: (%d) '%s'+char(%x)", n, buf, buf[n-1]); + + if (!fail) { + char *msg = NULL; + /* Websocket requests compat. */ + if ((msg = strstr(buf, "GET /")) && strlen(msg) > 5) { + char cmd[256] = { 0 }; + sscanf(&msg[5], "%s\n", cmd); + params = strchr(cmd, '/'); + if (params) + *(params++) = '|'; + params = strchr(cmd, '/'); + if (params) + *(params++) = '\0'; + wskey = strstr(msg, "Sec-WebSocket-Key"); + if (wskey) { + char *eol = strchr(wskey, '\r'); + if (eol) *eol = '\0'; + wskey = strchr(wskey, ':'); + wskey++; + while ((*wskey) == ' ') wskey++; // ltrim + } + n = sprintf(buf, "%s", cmd); + } + + params = strchr(buf, '|'); + if (params != NULL) + *(params++) = '\0'; + + if (opt_debug && opt_protocol && n > 0) + applog(LOG_DEBUG, "API: exec command %s(%s)", buf, params); + + for (i = 0; i < CMDMAX; i++) { + if (strcmp(buf, cmds[i].name) == 0) { + if (params && strlen(params)) { + // remove possible trailing | + if (params[strlen(params) - 1] == '|') + params[strlen(params) - 1] = '\0'; + } + result = (cmds[i].func)(params); + if (wskey) { + websocket_handshake(c, result, wskey); + break; + } + send_result(c, result); + break; + } + } + CLOSESOCKET(c); + } + } + } + + CLOSESOCKET(*apisock); + free(apisock); + free(buffer); +} + +/* external access */ +void *api_thread(void *userdata) +{ + struct thr_info *mythr = (struct thr_info*)userdata; + + startup = time(NULL); + api(); + tq_freeze(mythr->q); + + if (bye) { + // quit command + proper_exit(1); + } + + return NULL; +} diff --git a/api/index.php b/api/index.php new file mode 100644 index 000000000..3844154da --- /dev/null +++ b/api/index.php @@ -0,0 +1,197 @@ +'local-sample.php', + //'EPSYTOUR'=>'epsytour.php', /* copy local.php file and edit target IP:PORT */ +); + +// 3 seconds max. +set_time_limit(3); +error_reporting(0); + +function getdataFromPears() +{ + global $host, $configs; + $data = array(); + foreach ($configs as $name => $conf) { + + $json = file_get_contents($host.$conf); + + $data[$name] = json_decode($json, TRUE); + } + return $data; +} + +function ignoreField($key) +{ + $ignored = array('API','VER','GPU','CARD','GPUS','CPU'); + return in_array($key, $ignored); +} + +function translateField($key) +{ + $intl = array(); + $intl['NAME'] = 'Software'; + $intl['VER'] = 'Version'; + + $intl['ALGO'] = 'Algorithm'; + $intl['GPUS'] = 'GPUs'; + $intl['CPUS'] = 'Threads'; + $intl['KHS'] = 'Hash rate (kH/s)'; + $intl['ACC'] = 'Accepted shares'; + $intl['ACCMN'] = 'Accepted / mn'; + $intl['REJ'] = 'Rejected'; + $intl['DIFF'] = 'Difficulty'; + $intl['UPTIME'] = 'Miner up time'; + $intl['TS'] = 'Last update'; + + $intl['TEMP'] = 'T°c'; + $intl['FAN'] = 'Fan %'; + $intl['FREQ'] = 'Freq.'; + $intl['PST'] = 'P-State'; + + if (isset($intl[$key])) + return $intl[$key]; + else + return $key; +} + +function translateValue($key,$val,$data=array()) +{ + switch ($key) { + case 'UPTIME': + $min = floor(intval($val) / 60); + $sec = intval($val) % 60; + $val = "${min}mn${sec}s"; + if ($min > 180) { + $hrs = floor($min / 60); + $min = $min % 60; + $val = "${hrs}h${min}mn"; + } + break; + case 'NAME': + $val = $data['NAME'].' '.$data['VER']; + break; + case 'FREQ': + $val = sprintf("%d MHz", round(floatval($val)/1000.0)); + break; + case 'TS': + $val = strftime("%H:%M:%S", (int) $val); + break; + } + return $val; +} + +function displayData($data) +{ + $htm = ''; + $totals = array(); + foreach ($data as $name => $stats) { + $htm .= ''."\n"; + $htm .= '\n"; + if (!empty($stats)) { + $summary = (array) $stats['summary']; + foreach ($summary as $key=>$val) { + if (!empty($val) && !ignoreField($key)) + $htm .= ''. + '\n"; + } + if (isset($summary['KHS'])) + @ $totals[$summary['ALGO']] += floatval($summary['KHS']); + foreach ($stats['threads'] as $g=>$gpu) { + $card = isset($gpu['CARD']) ? $gpu['CARD'] : ''; + $htm .= '\n"; + foreach ($gpu as $key=>$val) { + if (!empty($val) && !ignoreField($key)) + $htm .= ''. + '\n"; + } + } + } + $htm .= "
'.$name."
'.translateField($key).''.translateValue($key, $val, $summary)."
'.$g." $card
'.translateField($key).''.translateValue($key, $val)."
\n"; + } + // totals + if (!empty($totals)) { + $htm .= '

Total Hash rate

'."\n"; + foreach ($totals as $algo => $hashrate) { + $htm .= '
  • '.$algo.":$hashrate kH/s
  • \n"; + } + $htm .= '
    '; + } + return $htm; +} + +$data = getdataFromPears(); + +?> + + + cpuminer rig api sample + + + + + + + +
    + +
    + + + + + diff --git a/api/local-sample.php b/api/local-sample.php new file mode 100644 index 000000000..1ca3c43ae --- /dev/null +++ b/api/local-sample.php @@ -0,0 +1,137 @@ + 0) { + $err = socket_last_error($socket); + echo "."; + if ($timeout > 1 && ($err == 115 || $err == 114)) { + $timeout--; + usleep(50); + $res = socket_connect($socket, API_HOST, $port); + continue; + } + $error = socket_strerror($err); + $msg = "socket connect($port) failed"; + echo "ERR: $msg '$error'\n"; + socket_close($socket); + return NULL; + } + + socket_set_block($socket); + + return $socket; +} + +function readsockline($socket) +{ + $line = ''; + while (true) { + $byte = socket_read($socket, 1); + if ($byte === false || $byte === '') + break; + if ($byte === "\0") + break; + $line .= $byte; + } + return $line; +} + + +function request($cmd) +{ + $socket = getsock(API_PORT); + if ($socket == null) + return NULL; + + socket_write($socket, $cmd, strlen($cmd)); + $line = readsockline($socket); + socket_close($socket); + + if (strlen($line) == 0) { + echo "WARN: '$cmd' returned nothing\n"; + return $line; + } + + echo "$cmd returned '$line'\n"; + + $data = array(); + + $objs = explode('|', $line); + foreach ($objs as $obj) + { + if (strlen($obj) > 0) + { + $items = explode(';', $obj); + $item = $items[0]; + $id = explode('=', $items[0], 2); + if (count($id) == 1) + $name = $id[0]; + else + $name = $id[0].$id[1]; + + if (strlen($name) == 0) + $name = 'null'; + + if (isset($data[$name])) { + $num = 1; + while (isset($data[$name.$num])) + $num++; + $name .= $num; + } + + $counter = 0; + foreach ($items as $item) + { + $id = explode('=', $item, 2); + if (count($id) == 2) + $data[$name][$id[0]] = $id[1]; + else + $data[$name][$counter] = $id[0]; + + $counter++; + } + + } + } + if ($cmd == 'summary') + return array_pop($data); + else + return $data; +} + +ob_start(); + +error_reporting(0); + +$summary = request('summary'); +$threads = request('threads'); +$histo = request('histo'); + +ob_end_clean(); /* swap to debug */ +//echo ob_get_clean()."\n"; + +header("Content-Type: application/json"); +echo json_encode(compact('summary', 'threads', 'histo'))."\n"; +?> diff --git a/api/websocket.htm b/api/websocket.htm new file mode 100644 index 000000000..e0cbbab5d --- /dev/null +++ b/api/websocket.htm @@ -0,0 +1,69 @@ + + + + + Simple WebSocket call sample + + +
    + + + diff --git a/aesb-x64.S b/asm/aesb-x64.S similarity index 97% rename from aesb-x64.S rename to asm/aesb-x64.S index 754aed338..75c04200f 100644 --- a/aesb-x64.S +++ b/asm/aesb-x64.S @@ -1,4 +1,4 @@ -#include "cpuminer-config.h" +#include #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/aesb-x86.S b/asm/aesb-x86.S similarity index 93% rename from aesb-x86.S rename to asm/aesb-x86.S index 4011ef663..ab3d1eab7 100644 --- a/aesb-x86.S +++ b/asm/aesb-x86.S @@ -1,4 +1,4 @@ -#include "cpuminer-config.h" +#include #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/asm/neoscrypt_asm.S b/asm/neoscrypt_asm.S new file mode 100644 index 000000000..d3eaf4da7 --- /dev/null +++ b/asm/neoscrypt_asm.S @@ -0,0 +1,757 @@ +/* + * Copyright (c) 2014 John Doering + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef _MSC_VER +/* arch defines */ +#include "miner.h" +#endif + +#if defined(__GNUC__) && !defined(__arm__) +#define ASM 1 +/* #define WIN64 0 */ +#endif + +#if (ASM) && (__x86_64__) + +/* neoscrypt_blkcpy(dst, src, len) = SSE2 based block memcpy(); + * len must be a multiple of 64 bytes aligned properly */ +.globl neoscrypt_blkcpy +.globl _neoscrypt_blkcpy +neoscrypt_blkcpy: +_neoscrypt_blkcpy: +#if (WIN64) + movq %rdi, %r10 + movq %rsi, %r11 + movq %rcx, %rdi + movq %rdx, %rsi + movq %r8, %rdx +#endif + xorq %rcx, %rcx + movl %edx, %ecx + shrl $6, %ecx + movq $64, %rax +.blkcpy: + movdqa 0(%rsi), %xmm0 + movdqa 16(%rsi), %xmm1 + movdqa 32(%rsi), %xmm2 + movdqa 48(%rsi), %xmm3 + movdqa %xmm0, 0(%rdi) + movdqa %xmm1, 16(%rdi) + movdqa %xmm2, 32(%rdi) + movdqa %xmm3, 48(%rdi) + addq %rax, %rdi + addq %rax, %rsi + decl %ecx + jnz .blkcpy +#if (WIN64) + movq %r10, %rdi + movq %r11, %rsi +#endif + ret + + +/* neoscrypt_blkswp(blkA, blkB, len) = SSE2 based block swapper; + * len must be a multiple of 64 bytes aligned properly */ +.globl neoscrypt_blkswp +.globl _neoscrypt_blkswp +neoscrypt_blkswp: +_neoscrypt_blkswp: +#if (WIN64) + movq %rdi, %r10 + movq %rsi, %r11 + movq %rcx, %rdi + movq %rdx, %rsi + movq %r8, %rdx +#endif + xorq %rcx, %rcx + movl %edx, %ecx + shrl $6, %ecx + movq $64, %rax +.blkswp: + movdqa 0(%rdi), %xmm0 + movdqa 16(%rdi), %xmm1 + movdqa 32(%rdi), %xmm2 + movdqa 48(%rdi), %xmm3 + movdqa 0(%rsi), %xmm4 + movdqa 16(%rsi), %xmm5 + movdqa 32(%rsi), %xmm8 + movdqa 48(%rsi), %xmm9 + movdqa %xmm0, 0(%rsi) + movdqa %xmm1, 16(%rsi) + movdqa %xmm2, 32(%rsi) + movdqa %xmm3, 48(%rsi) + movdqa %xmm4, 0(%rdi) + movdqa %xmm5, 16(%rdi) + movdqa %xmm8, 32(%rdi) + movdqa %xmm9, 48(%rdi) + addq %rax, %rdi + addq %rax, %rsi + decl %ecx + jnz .blkswp +#if (WIN64) + movq %r10, %rdi + movq %r11, %rsi +#endif + ret + + +/* neoscrypt_blkxor(dst, src, len) = SSE2 based block XOR engine; + * len must be a multiple of 64 bytes aligned properly */ +.globl neoscrypt_blkxor +.globl _neoscrypt_blkxor +neoscrypt_blkxor: +_neoscrypt_blkxor: +#if (WIN64) + movq %rdi, %r10 + movq %rsi, %r11 + movq %rcx, %rdi + movq %rdx, %rsi + movq %r8, %rdx +#endif + xorq %rcx, %rcx + movl %edx, %ecx + shrl $6, %ecx + movq $64, %rax +.blkxor: + movdqa 0(%rdi), %xmm0 + movdqa 16(%rdi), %xmm1 + movdqa 32(%rdi), %xmm2 + movdqa 48(%rdi), %xmm3 + movdqa 0(%rsi), %xmm4 + movdqa 16(%rsi), %xmm5 + movdqa 32(%rsi), %xmm8 + movdqa 48(%rsi), %xmm9 + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm8, %xmm2 + pxor %xmm9, %xmm3 + movdqa %xmm0, 0(%rdi) + movdqa %xmm1, 16(%rdi) + movdqa %xmm2, 32(%rdi) + movdqa %xmm3, 48(%rdi) + addq %rax, %rdi + addq %rax, %rsi + decl %ecx + jnz .blkxor +#if (WIN64) + movq %r10, %rdi + movq %r11, %rsi +#endif + ret + + +/* neoscrypt_salsa(mem, rounds) = SSE2 based Salsa20; + * mem must be aligned properly, rounds must be a multiple of 2 */ +.globl neoscrypt_salsa +.globl _neoscrypt_salsa +neoscrypt_salsa: +_neoscrypt_salsa: +#if (WIN64) + movq %rdi, %r10 + movq %rsi, %r11 + movq %rcx, %rdi + movq %rdx, %rsi +#endif + xorq %rcx, %rcx + movl %esi, %ecx + shrl $1, %ecx + movdqa 0(%rdi), %xmm0 + movdqa %xmm0, %xmm12 + movdqa 16(%rdi), %xmm1 + movdqa %xmm1, %xmm13 + movdqa 32(%rdi), %xmm2 + movdqa %xmm2, %xmm14 + movdqa 48(%rdi), %xmm3 + movdqa %xmm3, %xmm15 +.salsa: + movdqa %xmm1, %xmm4 + paddd %xmm0, %xmm4 + movdqa %xmm4, %xmm5 + pslld $7, %xmm4 + psrld $25, %xmm5 + pxor %xmm4, %xmm3 + movdqa %xmm0, %xmm4 + pxor %xmm5, %xmm3 + paddd %xmm3, %xmm4 + movdqa %xmm4, %xmm5 + pslld $9, %xmm4 + psrld $23, %xmm5 + pxor %xmm4, %xmm2 + movdqa %xmm3, %xmm4 + pxor %xmm5, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + paddd %xmm2, %xmm4 + movdqa %xmm4, %xmm5 + pslld $13, %xmm4 + psrld $19, %xmm5 + pxor %xmm4, %xmm1 + movdqa %xmm2, %xmm4 + pxor %xmm5, %xmm1 + pshufd $0x4E, %xmm2, %xmm2 + paddd %xmm1, %xmm4 + movdqa %xmm4, %xmm5 + pslld $18, %xmm4 + psrld $14, %xmm5 + pxor %xmm4, %xmm0 + movdqa %xmm3, %xmm4 + pxor %xmm5, %xmm0 + pshufd $0x39, %xmm1, %xmm1 + paddd %xmm0, %xmm4 + movdqa %xmm4, %xmm5 + pslld $7, %xmm4 + psrld $25, %xmm5 + pxor %xmm4, %xmm1 + movdqa %xmm0, %xmm4 + pxor %xmm5, %xmm1 + paddd %xmm1, %xmm4 + movdqa %xmm4, %xmm5 + pslld $9, %xmm4 + psrld $23, %xmm5 + pxor %xmm4, %xmm2 + movdqa %xmm1, %xmm4 + pxor %xmm5, %xmm2 + pshufd $0x93, %xmm1, %xmm1 + paddd %xmm2, %xmm4 + movdqa %xmm4, %xmm5 + pslld $13, %xmm4 + psrld $19, %xmm5 + pxor %xmm4, %xmm3 + movdqa %xmm2, %xmm4 + pxor %xmm5, %xmm3 + pshufd $0x4E, %xmm2, %xmm2 + paddd %xmm3, %xmm4 + movdqa %xmm4, %xmm5 + pslld $18, %xmm4 + psrld $14, %xmm5 + pxor %xmm4, %xmm0 + pshufd $0x39, %xmm3, %xmm3 + pxor %xmm5, %xmm0 + decl %ecx + jnz .salsa + + paddd %xmm12, %xmm0 + movdqa %xmm0, 0(%rdi) + paddd %xmm13, %xmm1 + movdqa %xmm1, 16(%rdi) + paddd %xmm14, %xmm2 + movdqa %xmm2, 32(%rdi) + paddd %xmm15, %xmm3 + movdqa %xmm3, 48(%rdi) +#if (WIN64) + movq %r10, %rdi + movq %r11, %rsi +#endif + ret + + +/* neoscrypt_salsa_tangle(mem, count) = Salsa20 SSE2 map switcher; + * correct map: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * SSE2 map: 0 5 10 15 12 1 6 11 8 13 2 7 4 9 14 3 */ +.globl neoscrypt_salsa_tangle +.globl _neoscrypt_salsa_tangle +neoscrypt_salsa_tangle: +_neoscrypt_salsa_tangle: +#if (WIN64) + movq %rdi, %r10 + movq %rsi, %r11 + movq %rcx, %rdi + movq %rdx, %rsi +#endif + xorq %rcx, %rcx + movl %esi, %ecx + movq $64, %r8 +.salsa_tangle: + movl 4(%rdi), %eax + movl 20(%rdi), %edx + movl %eax, 20(%rdi) + movl %edx, 4(%rdi) + movl 8(%rdi), %eax + movl 40(%rdi), %edx + movl %eax, 40(%rdi) + movl %edx, 8(%rdi) + movl 12(%rdi), %eax + movl 60(%rdi), %edx + movl %eax, 60(%rdi) + movl %edx, 12(%rdi) + movl 16(%rdi), %eax + movl 48(%rdi), %edx + movl %eax, 48(%rdi) + movl %edx, 16(%rdi) + movl 28(%rdi), %eax + movl 44(%rdi), %edx + movl %eax, 44(%rdi) + movl %edx, 28(%rdi) + movl 36(%rdi), %eax + movl 52(%rdi), %edx + movl %eax, 52(%rdi) + movl %edx, 36(%rdi) + addq %r8, %rdi + decl %ecx + jnz .salsa_tangle +#if (WIN64) + movq %r10, %rdi + movq %r11, %rsi +#endif + ret + + +/* neoscrypt_chacha(mem, rounds) = SSE2 based ChaCha20; + * mem must be aligned properly, rounds must be a multiple of 2 */ +.globl neoscrypt_chacha +.globl _neoscrypt_chacha +neoscrypt_chacha: +_neoscrypt_chacha: +#if (WIN64) + movq %rdi, %r10 + movq %rsi, %r11 + movq %rcx, %rdi + movq %rdx, %rsi +#endif + xorq %rcx, %rcx + movl %esi, %ecx + shrl $1, %ecx + movdqa 0(%rdi), %xmm0 + movdqa %xmm0, %xmm12 + movdqa 16(%rdi), %xmm1 + movdqa %xmm1, %xmm13 + movdqa 32(%rdi), %xmm2 + movdqa %xmm2, %xmm14 + movdqa 48(%rdi), %xmm3 + movdqa %xmm3, %xmm15 +.chacha: + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + pshuflw $0xB1, %xmm3, %xmm3 + pshufhw $0xB1, %xmm3, %xmm3 + paddd %xmm3, %xmm2 + pxor %xmm2, %xmm1 + movdqa %xmm1, %xmm4 + pslld $12, %xmm1 + psrld $20, %xmm4 + pxor %xmm4, %xmm1 + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + movdqa %xmm3, %xmm4 + pslld $8, %xmm3 + psrld $24, %xmm4 + pxor %xmm4, %xmm3 + pshufd $0x93, %xmm0, %xmm0 + paddd %xmm3, %xmm2 + pshufd $0x4E, %xmm3, %xmm3 + pxor %xmm2, %xmm1 + pshufd $0x39, %xmm2, %xmm2 + movdqa %xmm1, %xmm4 + pslld $7, %xmm1 + psrld $25, %xmm4 + pxor %xmm4, %xmm1 + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + pshuflw $0xB1, %xmm3, %xmm3 + pshufhw $0xB1, %xmm3, %xmm3 + paddd %xmm3, %xmm2 + pxor %xmm2, %xmm1 + movdqa %xmm1, %xmm4 + pslld $12, %xmm1 + psrld $20, %xmm4 + pxor %xmm4, %xmm1 + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + movdqa %xmm3, %xmm4 + pslld $8, %xmm3 + psrld $24, %xmm4 + pxor %xmm4, %xmm3 + pshufd $0x39, %xmm0, %xmm0 + paddd %xmm3, %xmm2 + pshufd $0x4E, %xmm3, %xmm3 + pxor %xmm2, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + movdqa %xmm1, %xmm4 + pslld $7, %xmm1 + psrld $25, %xmm4 + pxor %xmm4, %xmm1 + decl %ecx + jnz .chacha + + paddd %xmm12, %xmm0 + movdqa %xmm0, 0(%rdi) + paddd %xmm13, %xmm1 + movdqa %xmm1, 16(%rdi) + paddd %xmm14, %xmm2 + movdqa %xmm2, 32(%rdi) + paddd %xmm15, %xmm3 + movdqa %xmm3, 48(%rdi) +#if (WIN64) + movq %r10, %rdi + movq %r11, %rsi +#endif + ret + +#endif /* (ASM) && (__x86_64__) */ + + +#if (ASM) && (__i386__) + +/* neoscrypt_blkcpy(dst, src, len) = SSE2 based block memcpy(); + * len must be a multiple of 64 bytes aligned properly */ +.globl neoscrypt_blkcpy +.globl _neoscrypt_blkcpy +neoscrypt_blkcpy: +_neoscrypt_blkcpy: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 16(%esp), %esi + movl 20(%esp), %ecx + shrl $6, %ecx + movl $64, %eax +.blkcpy: + movdqa 0(%esi), %xmm0 + movdqa 16(%esi), %xmm1 + movdqa 32(%esi), %xmm2 + movdqa 48(%esi), %xmm3 + movdqa %xmm0, 0(%edi) + movdqa %xmm1, 16(%edi) + movdqa %xmm2, 32(%edi) + movdqa %xmm3, 48(%edi) + addl %eax, %edi + add %eax, %esi + decl %ecx + jnz .blkcpy + + popl %esi + popl %edi + ret + + +/* neoscrypt_blkswp(blkA, blkB, len) = SSE2 based block swapper; + * len must be a multiple of 64 bytes aligned properly */ +.globl neoscrypt_blkswp +.globl _neoscrypt_blkswp +neoscrypt_blkswp: +_neoscrypt_blkswp: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 16(%esp), %esi + movl 20(%esp), %ecx + shrl $6, %ecx + movl $64, %eax +.blkswp: + movdqa 0(%edi), %xmm0 + movdqa 16(%edi), %xmm1 + movdqa 32(%edi), %xmm2 + movdqa 48(%edi), %xmm3 + movdqa 0(%esi), %xmm4 + movdqa 16(%esi), %xmm5 + movdqa 32(%esi), %xmm6 + movdqa 48(%esi), %xmm7 + movdqa %xmm0, 0(%esi) + movdqa %xmm1, 16(%esi) + movdqa %xmm2, 32(%esi) + movdqa %xmm3, 48(%esi) + movdqa %xmm4, 0(%edi) + movdqa %xmm5, 16(%edi) + movdqa %xmm6, 32(%edi) + movdqa %xmm7, 48(%edi) + addl %eax, %edi + addl %eax, %esi + decl %ecx + jnz .blkswp + + popl %esi + popl %edi + ret + + +/* neoscrypt_blkxor(dst, src, len) = SSE2 based block XOR engine; + * len must be a multiple of 64 bytes aligned properly */ +.globl neoscrypt_blkxor +.globl _neoscrypt_blkxor +neoscrypt_blkxor: +_neoscrypt_blkxor: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 16(%esp), %esi + movl 20(%esp), %ecx + shrl $6, %ecx + movl $64, %eax +.blkxor: + movdqa 0(%edi), %xmm0 + movdqa 16(%edi), %xmm1 + movdqa 32(%edi), %xmm2 + movdqa 48(%edi), %xmm3 + movdqa 0(%esi), %xmm4 + movdqa 16(%esi), %xmm5 + movdqa 32(%esi), %xmm6 + movdqa 48(%esi), %xmm7 + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm6, %xmm2 + pxor %xmm7, %xmm3 + movdqa %xmm0, 0(%edi) + movdqa %xmm1, 16(%edi) + movdqa %xmm2, 32(%edi) + movdqa %xmm3, 48(%edi) + addl %eax, %edi + addl %eax, %esi + decl %ecx + jnz .blkxor + + popl %esi + popl %edi + ret + + +/* neoscrypt_salsa(mem, rounds) = SSE2 based Salsa20; + * mem must be aligned properly, rounds must be a multiple of 2 */ +.globl neoscrypt_salsa +.globl _neoscrypt_salsa +neoscrypt_salsa: +_neoscrypt_salsa: + movl 4(%esp), %edx + movl 8(%esp), %ecx + shrl $1, %ecx + movdqa 0(%edx), %xmm0 + movdqa %xmm0, %xmm6 + movdqa 16(%edx), %xmm1 + movdqa %xmm1, %xmm7 + subl $32, %esp + movdqa 32(%edx), %xmm2 + movdqu %xmm2, 0(%esp) + movdqa 48(%edx), %xmm3 + movdqu %xmm3, 16(%esp) +.salsa: + movdqa %xmm1, %xmm4 + paddd %xmm0, %xmm4 + movdqa %xmm4, %xmm5 + pslld $7, %xmm4 + psrld $25, %xmm5 + pxor %xmm4, %xmm3 + movdqa %xmm0, %xmm4 + pxor %xmm5, %xmm3 + paddd %xmm3, %xmm4 + movdqa %xmm4, %xmm5 + pslld $9, %xmm4 + psrld $23, %xmm5 + pxor %xmm4, %xmm2 + movdqa %xmm3, %xmm4 + pxor %xmm5, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + paddd %xmm2, %xmm4 + movdqa %xmm4, %xmm5 + pslld $13, %xmm4 + psrld $19, %xmm5 + pxor %xmm4, %xmm1 + movdqa %xmm2, %xmm4 + pxor %xmm5, %xmm1 + pshufd $0x4E, %xmm2, %xmm2 + paddd %xmm1, %xmm4 + movdqa %xmm4, %xmm5 + pslld $18, %xmm4 + psrld $14, %xmm5 + pxor %xmm4, %xmm0 + movdqa %xmm3, %xmm4 + pxor %xmm5, %xmm0 + pshufd $0x39, %xmm1, %xmm1 + paddd %xmm0, %xmm4 + movdqa %xmm4, %xmm5 + pslld $7, %xmm4 + psrld $25, %xmm5 + pxor %xmm4, %xmm1 + movdqa %xmm0, %xmm4 + pxor %xmm5, %xmm1 + paddd %xmm1, %xmm4 + movdqa %xmm4, %xmm5 + pslld $9, %xmm4 + psrld $23, %xmm5 + pxor %xmm4, %xmm2 + movdqa %xmm1, %xmm4 + pxor %xmm5, %xmm2 + pshufd $0x93, %xmm1, %xmm1 + paddd %xmm2, %xmm4 + movdqa %xmm4, %xmm5 + pslld $13, %xmm4 + psrld $19, %xmm5 + pxor %xmm4, %xmm3 + movdqa %xmm2, %xmm4 + pxor %xmm5, %xmm3 + pshufd $0x4E, %xmm2, %xmm2 + paddd %xmm3, %xmm4 + movdqa %xmm4, %xmm5 + pslld $18, %xmm4 + psrld $14, %xmm5 + pxor %xmm4, %xmm0 + pshufd $0x39, %xmm3, %xmm3 + pxor %xmm5, %xmm0 + decl %ecx + jnz .salsa + + paddd %xmm6, %xmm0 + movdqa %xmm0, 0(%edx) + paddd %xmm7, %xmm1 + movdqa %xmm1, 16(%edx) + movdqu 0(%esp), %xmm6 + paddd %xmm6, %xmm2 + movdqa %xmm2, 32(%edx) + movdqu 16(%esp), %xmm7 + paddd %xmm7, %xmm3 + movdqa %xmm3, 48(%edx) + addl $32, %esp + ret + + +/* neoscrypt_salsa_tangle(mem, count) = Salsa20 SSE2 map switcher; + * correct map: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * SSE2 map: 0 5 10 15 12 1 6 11 8 13 2 7 4 9 14 3 */ +.globl neoscrypt_salsa_tangle +.globl _neoscrypt_salsa_tangle +neoscrypt_salsa_tangle: +_neoscrypt_salsa_tangle: + pushl %ebx + push %ebp + movl 12(%esp), %ebp + movl 16(%esp), %ecx + movl $64, %ebx +.salsa_tangle: + movl 4(%ebp), %eax + movl 20(%ebp), %edx + movl %eax, 20(%ebp) + movl %edx, 4(%ebp) + movl 8(%ebp), %eax + movl 40(%ebp), %edx + movl %eax, 40(%ebp) + movl %edx, 8(%ebp) + movl 12(%ebp), %eax + movl 60(%ebp), %edx + movl %eax, 60(%ebp) + movl %edx, 12(%ebp) + movl 16(%ebp), %eax + movl 48(%ebp), %edx + movl %eax, 48(%ebp) + movl %edx, 16(%ebp) + movl 28(%ebp), %eax + movl 44(%ebp), %edx + movl %eax, 44(%ebp) + movl %edx, 28(%ebp) + movl 36(%ebp), %eax + movl 52(%ebp), %edx + movl %eax, 52(%ebp) + movl %edx, 36(%ebp) + addl %ebx, %ebp + decl %ecx + jnz .salsa_tangle + + popl %ebp + popl %ebx + ret + + +/* neoscrypt_chacha(mem, rounds) = SSE2 based ChaCha20; + * mem must be aligned properly, rounds must be a multiple of 2 */ +.globl neoscrypt_chacha +.globl _neoscrypt_chacha +neoscrypt_chacha: +_neoscrypt_chacha: + movl 4(%esp), %edx + movl 8(%esp), %ecx + shrl $1, %ecx + movdqa 0(%edx), %xmm0 + movdqa %xmm0, %xmm5 + movdqa 16(%edx), %xmm1 + movdqa %xmm1, %xmm6 + movdqa 32(%edx), %xmm2 + movdqa %xmm2, %xmm7 + subl $16, %esp + movdqa 48(%edx), %xmm3 + movdqu %xmm3, 0(%esp) +.chacha: + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + pshuflw $0xB1, %xmm3, %xmm3 + pshufhw $0xB1, %xmm3, %xmm3 + paddd %xmm3, %xmm2 + pxor %xmm2, %xmm1 + movdqa %xmm1, %xmm4 + pslld $12, %xmm1 + psrld $20, %xmm4 + pxor %xmm4, %xmm1 + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + movdqa %xmm3, %xmm4 + pslld $8, %xmm3 + psrld $24, %xmm4 + pxor %xmm4, %xmm3 + pshufd $0x93, %xmm0, %xmm0 + paddd %xmm3, %xmm2 + pshufd $0x4E, %xmm3, %xmm3 + pxor %xmm2, %xmm1 + pshufd $0x39, %xmm2, %xmm2 + movdqa %xmm1, %xmm4 + pslld $7, %xmm1 + psrld $25, %xmm4 + pxor %xmm4, %xmm1 + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + pshuflw $0xB1, %xmm3, %xmm3 + pshufhw $0xB1, %xmm3, %xmm3 + paddd %xmm3, %xmm2 + pxor %xmm2, %xmm1 + movdqa %xmm1, %xmm4 + pslld $12, %xmm1 + psrld $20, %xmm4 + pxor %xmm4, %xmm1 + paddd %xmm1, %xmm0 + pxor %xmm0, %xmm3 + movdqa %xmm3, %xmm4 + pslld $8, %xmm3 + psrld $24, %xmm4 + pxor %xmm4, %xmm3 + pshufd $0x39, %xmm0, %xmm0 + paddd %xmm3, %xmm2 + pshufd $0x4E, %xmm3, %xmm3 + pxor %xmm2, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + movdqa %xmm1, %xmm4 + pslld $7, %xmm1 + psrld $25, %xmm4 + pxor %xmm4, %xmm1 + decl %ecx + jnz .chacha + + paddd %xmm5, %xmm0 + movdqa %xmm0, 0(%edx) + paddd %xmm6, %xmm1 + movdqa %xmm1, 16(%edx) + paddd %xmm7, %xmm2 + movdqa %xmm2, 32(%edx) + movdqu 0(%esp), %xmm7 + paddd %xmm7, %xmm3 + movdqa %xmm3, 48(%edx) + addl $16, %esp + ret + +#endif /* (ASM) && (__i386__) */ diff --git a/scrypt-arm.S b/asm/scrypt-arm.S similarity index 99% rename from scrypt-arm.S rename to asm/scrypt-arm.S index 5be3b0e9d..437bcc333 100644 --- a/scrypt-arm.S +++ b/asm/scrypt-arm.S @@ -7,7 +7,7 @@ * any later version. See COPYING for more details. */ -#include "cpuminer-config.h" +#include #if defined(USE_ASM) && defined(__arm__) && defined(__APCS_32__) diff --git a/scrypt-x64.S b/asm/scrypt-x64.S similarity index 99% rename from scrypt-x64.S rename to asm/scrypt-x64.S index f9185d490..b45a2879f 100644 --- a/scrypt-x64.S +++ b/asm/scrypt-x64.S @@ -24,7 +24,7 @@ * SUCH DAMAGE. */ -#include "cpuminer-config.h" +#include #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/scrypt-x86.S b/asm/scrypt-x86.S similarity index 99% rename from scrypt-x86.S rename to asm/scrypt-x86.S index 5ab7eda65..9cff123d9 100644 --- a/scrypt-x86.S +++ b/asm/scrypt-x86.S @@ -24,7 +24,7 @@ * SUCH DAMAGE. */ -#include "cpuminer-config.h" +#include #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/sha2-arm.S b/asm/sha2-arm.S similarity index 99% rename from sha2-arm.S rename to asm/sha2-arm.S index bd7fdc5cb..6ba9fa977 100644 --- a/sha2-arm.S +++ b/asm/sha2-arm.S @@ -7,7 +7,7 @@ * any later version. See COPYING for more details. */ -#include "cpuminer-config.h" +#include #if defined(USE_ASM) && defined(__arm__) && defined(__APCS_32__) diff --git a/sha2-x64.S b/asm/sha2-x64.S similarity index 99% rename from sha2-x64.S rename to asm/sha2-x64.S index 0326d9d4a..7b815d148 100644 --- a/sha2-x64.S +++ b/asm/sha2-x64.S @@ -7,7 +7,7 @@ * any later version. See COPYING for more details. */ -#include "cpuminer-config.h" +#include #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/sha2-x86.S b/asm/sha2-x86.S similarity index 99% rename from sha2-x86.S rename to asm/sha2-x86.S index e2eb112a9..5ff4f4b28 100644 --- a/sha2-x86.S +++ b/asm/sha2-x86.S @@ -7,7 +7,7 @@ * any later version. See COPYING for more details. */ -#include "cpuminer-config.h" +#include #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/autogen.sh b/autogen.sh index 989604a9b..0a210f090 100755 --- a/autogen.sh +++ b/autogen.sh @@ -7,6 +7,7 @@ set -e aclocal autoheader -automake --gnu --add-missing --copy +automake --foreign --add-missing --force-missing --copy +# automake --gnu --add-missing --copy autoconf diff --git a/blake.c b/blake.c deleted file mode 100644 index 9a7bfffb7..000000000 --- a/blake.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "cpuminer-config.h" -#include "miner.h" - -#include -#include - -#include "sha3/sph_blake.h" - -/* Move init out of loop, so init once externally, and then use one single memcpy with that bigger memory block */ -typedef struct { - sph_blake256_context blake1; -} blakehash_context_holder; - -static blakehash_context_holder base_contexts; - -void init_blakehash_contexts() -{ - sph_blake256_init(&base_contexts.blake1); -} - -static void blakehash(void *state, const void *input) -{ - blakehash_context_holder ctx; -//an array of uint32 - uint32_t hashA[8]; - - -//do one memcopy to get fresh contexts, its faster even with a larger block then issuing 9 memcopies - memcpy(&ctx, &base_contexts, sizeof(base_contexts)); - - sph_blake256 (&ctx.blake1, input, 80); - sph_blake256_close (&ctx.blake1, hashA); //0 - memcpy(state, hashA, 32); - -} - -int scanhash_blake(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t n = pdata[19] - 1; - const uint32_t first_nonce = pdata[19]; - const uint32_t Htarg = ptarget[7]; - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - - //char testdata[] = {"\x70\x00\x00\x00\x5d\x38\x5b\xa1\x14\xd0\x79\x97\x0b\x29\xa9\x41\x8f\xd0\x54\x9e\x7d\x68\xa9\x5c\x7f\x16\x86\x21\xa3\x14\x20\x10\x00\x00\x00\x00\x57\x85\x86\xd1\x49\xfd\x07\xb2\x2f\x3a\x8a\x34\x7c\x51\x6d\xe7\x05\x2f\x03\x4d\x2b\x76\xff\x68\xe0\xd6\xec\xff\x9b\x77\xa4\x54\x89\xe3\xfd\x51\x17\x32\x01\x1d\xf0\x73\x10\x00"}; - - //we need bigendian data... - //lessons learned: do NOT endianchange directly in pdata, this will all proof-of-works be considered as stale from minerd.... - int kk=0; - for (; kk < 32; kk++) - { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; - -// if (opt_debug) -// { -// applog(LOG_DEBUG, "Thr: %02d, firstN: %08x, maxN: %08x, ToDo: %d", thr_id, first_nonce, max_nonce, max_nonce-first_nonce); -// } - - /* I'm to lazy to put the loop in an inline function... so dirty copy'n'paste.... */ - /* i know that i could set a variable, but i don't know how the compiler will optimize it, not that then the cpu needs to load the value *everytime* in a register */ - if (ptarget[7]==0) { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - blakehash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFFFF)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - blakehash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFFF0)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - blakehash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFF00)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - blakehash(hash64, &endiandata); - if (((hash64[7]&0xFFFFF000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else if (ptarget[7]<=0xFFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - blakehash(hash64, &endiandata); - if (((hash64[7]&0xFFFF0000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - blakehash(hash64, &endiandata); - if (fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - - - *hashes_done = n - first_nonce + 1; - pdata[19] = n; - return 0; -} diff --git a/build-linux-arm.sh b/build-linux-arm.sh new file mode 100755 index 000000000..48a1c70d6 --- /dev/null +++ b/build-linux-arm.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Linux build, optimised for ARM devices + +if [ ! -e configure ]; then + echo "Creating configure..." + rm -rf autom4te.cache + rm -f Makefile.in aclocal.m4 autom4te.cache compat/Makefile.in + rm -f compile config.guess config.sub config.status configure + rm -f cpuminer-config.h.in depcomp install-sh missing + if ./autogen.sh; then + echo " => done." + else + exit 1 + fi +fi + +if [ -e Makefile ]; then + echo "Cleaning previous build..." + make distclean + echo " => done." +fi + +echo "Configuring..." + +# --disable-assembly: some ASM code doesn't build on ARM +# Note: we don't enable -flto, it doesn't bring anything here but slows down +# the build a lot. If needed, just add -flto to the CFLAGS string. +# normal build. +./configure --with-crypto --with-curl --disable-assembly CC=gcc CXX=g++ CFLAGS="-Ofast -fuse-linker-plugin -ftree-loop-if-convert-stores -march=native" LDFLAGS="-march=native" + +# debug build +#./configure --with-crypto --with-curl --disable-assembly CC=gcc CXX=g++ CFLAGS="-O0 -g3 -fuse-linker-plugin -ftree-loop-if-convert-stores -march=native" LDFLAGS="-g3 -march=native" + +[ $? = 0 ] || exit $? +echo " => done." + +if [ -z "$NPROC" ]; then + NPROC=$(nproc 2>/dev/null) + NPROC=${NPROC:-1} +fi + +echo "Compiling on $NPROC processes..." + +make -j $NPROC + +if [ $? != 0 ]; then + echo "Compilation failed (make=$?)". + echo "Common causes: missing libjansson-dev libcurl4-openssl-dev libssl-dev" + echo "If you pulled updates into this directory, remove configure and try again." + exit 1 +fi +echo " => done." + +echo '$ ls -l cpuminer' +ls -l cpuminer + +echo "Stripping..." + +strip -s cpuminer + +[ $? = 0 ] || exit $? +echo " => done." diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..3a493ea26 --- /dev/null +++ b/build.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +if [ "$OS" = "Windows_NT" ]; then + ./mingw64.sh + exit 0 +fi + +make clean || echo clean + +rm -f config.status +./autogen.sh + +if [[ "$OSTYPE" == "darwin"* ]]; then + ./nomacro.pl + ./configure \ + CFLAGS="-march=native -O2 -Ofast -flto -DUSE_ASM -pg" \ + --with-crypto=/usr/local/opt/openssl \ + --with-curl=/usr/local/opt/curl + make -j4 + strip cpuminer + exit 0 +fi + +# Linux build + +# Ubuntu 10.04 (gcc 4.4) +# extracflags="-O3 -march=native -Wall -D_REENTRANT -funroll-loops -fvariable-expansion-in-unroller -fmerge-all-constants -fbranch-target-load-optimize2 -fsched2-use-superblocks -falign-loops=16 -falign-functions=16 -falign-jumps=16 -falign-labels=16" + +# Debian 7.7 / Ubuntu 14.04 (gcc 4.7+) +extracflags="$extracflags -Ofast -flto -fuse-linker-plugin -ftree-loop-if-convert-stores" + +if [ ! "0" = `cat /proc/cpuinfo | grep -c avx` ]; then + # march native doesn't always works, ex. some Pentium Gxxx (no avx) + extracflags="$extracflags -march=native" +fi + +./configure --with-crypto --with-curl CFLAGS="-O2 $extracflags -DUSE_ASM -pg" + +make -j 4 + +strip -s cpuminer diff --git a/compat.h b/compat.h index 283fc9b61..9f2611fe4 100644 --- a/compat.h +++ b/compat.h @@ -4,6 +4,11 @@ #ifdef WIN32 #include +#include + +#ifndef localtime_r +#define localtime_r(src, dst) localtime_s(dst, src) +#endif #define sleep(secs) Sleep((secs) * 1000) @@ -11,11 +16,88 @@ enum { PRIO_PROCESS = 0, }; -static inline int setpriority(int which, int who, int prio) +extern int opt_priority; +static __inline int setpriority(int which, int who, int prio) { - return -!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); + switch (opt_priority) { + case 5: + prio = THREAD_PRIORITY_TIME_CRITICAL; + break; + case 4: + prio = THREAD_PRIORITY_HIGHEST; + break; + case 3: + prio = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case 2: + prio = THREAD_PRIORITY_NORMAL; + break; + case 1: + prio = THREAD_PRIORITY_BELOW_NORMAL; + break; + case 0: + default: + prio = THREAD_PRIORITY_IDLE; + } + return -!SetThreadPriority(GetCurrentThread(), prio); } +#ifdef _MSC_VER +#define snprintf(...) _snprintf(__VA_ARGS__) +#define strdup(...) _strdup(__VA_ARGS__) +#define strncasecmp(x,y,z) _strnicmp(x,y,z) +#define strcasecmp(x,y) _stricmp(x,y) +#define __func__ __FUNCTION__ +#define __thread __declspec(thread) +#define _ALIGN(x) __declspec(align(x)) +typedef int ssize_t; + +__inline int msver(void) { + switch (_MSC_VER) { + case 1500: return 2008; + case 1600: return 2010; + case 1700: return 2012; + case 1800: return 2013; + case 1900: return 2015; + default: return (_MSC_VER/100); + } +} + +#include +// This static var is made to be compatible with linux/mingw (no free on string result) +// This is not thread safe but we only use that once on process start +static char dirname_buffer[_MAX_PATH] = { 0 }; +static __inline char * dirname(char *file) { + char drive[_MAX_DRIVE] = { 0 }; + char dir[_MAX_DIR] = { 0 }; + char fname[_MAX_FNAME], ext[_MAX_EXT]; + _splitpath_s(file, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT); + if (dir && strlen(dir) && dir[strlen(dir)-1] == '\\') { + dir[strlen(dir) - 1] = '\0'; + } + sprintf(dirname_buffer, "%s%s", drive, dir); + return &dirname_buffer[0]; +} +#endif + #endif /* WIN32 */ +#ifndef _MSC_VER +#define _ALIGN(x) __attribute__ ((aligned(x))) +#endif + +#undef unlikely +#undef likely +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define unlikely(expr) (__builtin_expect(!!(expr), 0)) +#define likely(expr) (__builtin_expect(!!(expr), 1)) +#else +#define unlikely(expr) (expr) +#define likely(expr) (expr) +#endif + +#ifndef WIN32 +#define MAX_PATH PATH_MAX +#endif + #endif /* __COMPAT_H__ */ diff --git a/compat/bionic/cpuminer-config.h b/compat/bionic/cpuminer-config.h new file mode 100644 index 000000000..b6bed8783 --- /dev/null +++ b/compat/bionic/cpuminer-config.h @@ -0,0 +1,128 @@ +/* cpuminer-config.h.in. Adapted for arm bionic (Android 5.1.1 Tegra K1) */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the declaration of `be32dec', and to 0 if you + don't. */ +#define HAVE_DECL_BE32DEC 0 + +/* Define to 1 if you have the declaration of `be32enc', and to 0 if you + don't. */ +#define HAVE_DECL_BE32ENC 0 + +/* Define to 1 if you have the declaration of `le16dec', and to 0 if you + don't. */ +#define HAVE_DECL_LE16DEC 0 + +/* Define to 1 if you have the declaration of `le16enc', and to 0 if you + don't. */ +#define HAVE_DECL_LE16ENC 0 + +/* Define to 1 if you have the declaration of `le32dec', and to 0 if you + don't. */ +#define HAVE_DECL_LE32DEC 0 + +/* Define to 1 if you have the declaration of `le32enc', and to 0 if you + don't. */ +#define HAVE_DECL_LE32ENC 0 + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSCTL_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "cpuminer-multi" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "cpuminer-multi" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "cpuminer-multi " VERSION + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "cpuminer-multi" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://github.com/tpruvot/cpuminer-multi" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION VERSION + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if assembly routines are wanted. */ +#define USE_ASM 1 + +/* Define to 1 if AVX assembly is available. */ +#define USE_AVX 1 + +/* Define to 1 if AVX2 assembly is available. */ +#define USE_AVX2 1 + +/* Define if __uint128_t is available */ +#undef USE_INT128 + +/* Define to 1 if XOP assembly is available. */ +#define USE_XOP 1 + +/* Define to `unsigned int' if does not define. */ +#undef size_t + diff --git a/compat/cpuminer-config.h b/compat/cpuminer-config.h new file mode 100644 index 000000000..ccd9fc52e --- /dev/null +++ b/compat/cpuminer-config.h @@ -0,0 +1,138 @@ +/* Generated on windows by mingw for VStudio */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if you have the declaration of `be32dec', and to 0 if you + don't. */ +#define HAVE_DECL_BE32DEC 0 + +/* Define to 1 if you have the declaration of `be32enc', and to 0 if you + don't. */ +#define HAVE_DECL_BE32ENC 0 + +/* Define to 1 if you have the declaration of `le16dec', and to 0 if you + don't. */ +#define HAVE_DECL_LE16DEC 0 + +/* Define to 1 if you have the declaration of `le16enc', and to 0 if you + don't. */ +#define HAVE_DECL_LE16ENC 0 + +/* Define to 1 if you have the declaration of `le32dec', and to 0 if you + don't. */ +#define HAVE_DECL_LE32DEC 0 + +/* Define to 1 if you have the declaration of `le32enc', and to 0 if you + don't. */ +#define HAVE_DECL_LE32ENC 0 + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYSLOG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCTL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "cpuminer-multi" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "cpuminer-multi" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "cpuminer-multi 1.3.7" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "cpuminer-multi" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.3.7" + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if assembly routines are wanted. */ +#define USE_ASM 1 + +/* Define to 1 if AVX assembly is available. */ +#define USE_AVX 1 + +/* Define to 1 if AVX2 assembly is available. */ +#define USE_AVX2 1 + +/* Define if __uint128_t is available */ +#define USE_INT128 1 + +/* Define to 1 if XOP assembly is available. */ +#define USE_XOP 1 + +/* Version number of package */ +#define VERSION "1.3.7" + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/compat/curl-for-windows/curl/include/curl/curl.h b/compat/curl-for-windows/curl/include/curl/curl.h new file mode 100644 index 000000000..d40b2dbbf --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/curl.h @@ -0,0 +1,2336 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * http://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * http://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#include "curlver.h" /* libcurl version defines */ +#include "curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURL; + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ +#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ +#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ +#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer + do not free in formfree */ +#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer + do not free in formfree */ +#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ +#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ +#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the + regular read callback to get the data + and pass the given pointer as custom + pointer */ + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char * b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, OBJECTPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, OBJECTPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, OBJECTPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, OBJECTPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, OBJECTPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, OBJECTPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, OBJECTPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, OBJECTPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, OBJECTPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, OBJECTPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, OBJECTPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, OBJECTPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), + + /* HTTP request, for odd commands like DELETE, TRACE and others */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, OBJECTPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, OBJECTPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, OBJECTPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, OBJECTPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, OBJECTPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, OBJECTPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, OBJECTPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, OBJECTPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, OBJECTPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, OBJECTPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, OBJECTPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, OBJECTPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), + + /* feed cookies into cookie engine */ + CINIT(COOKIELIST, OBJECTPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, OBJECTPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, OBJECTPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, OBJECTPOINT, 173), + CINIT(PASSWORD, OBJECTPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, OBJECTPOINT, 175), + CINIT(PROXYPASSWORD, OBJECTPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, OBJECTPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, OBJECTPOINT, 186), + + /* set the SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, OBJECTPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, OBJECTPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, OBJECTPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, OBJECTPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_QSOSSL = 4, + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10 +} curl_sslbackend; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 43 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + +typedef void CURLSH; + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ +#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ +#define CURL_VERSION_CONV (1<<12) /* character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* GSS-API is supported */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/compat/curl-for-windows/curl/include/curl/curlbuild.h b/compat/curl-for-windows/curl/include/curl/curlbuild.h new file mode 100644 index 000000000..aa53673f3 --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/curlbuild.h @@ -0,0 +1,180 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif +#ifdef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +/* #undef CURL_PULL_SYS_TYPES_H */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +/* #undef CURL_PULL_STDINT_H */ +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +/* #undef CURL_PULL_INTTYPES_H */ +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CURL_SIZEOF_LONG 4 + +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t + +/* on windows socklen_t is in here */ +#ifdef _WIN32 +# include +# include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* Signed integral data type used for curl_off_t. */ +#define CURL_TYPEOF_CURL_OFF_T long long + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_T "lld" + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_TU "llu" + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#define CURL_FORMAT_OFF_T "%lld" + +/* The size of `curl_off_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_OFF_T 8 + +/* curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_T LL + +/* unsigned curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_TU ULL + +#endif /* __CURL_CURLBUILD_H */ diff --git a/compat/curl-for-windows/curl/include/curl/curlrules.h b/compat/curl-for-windows/curl/include/curl/curlrules.h new file mode 100644 index 000000000..7c2ede35b --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/curlrules.h @@ -0,0 +1,262 @@ +#ifndef __CURL_CURLRULES_H +#define __CURL_CURLRULES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by curl/curl.h when an application is + * being built using an already built libcurl library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the curlbuild.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the libcurl development mailing list: + * http://cool.haxx.se/mailman/listinfo/curl-library/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built libcurl library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +#endif + +#ifndef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __curl_rule_01__ + [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * curl_off_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_02__ + [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; + +/* + * Verify at compile time that the size of curl_off_t as reported + * by sizeof() is greater or equal than the one reported for long + * for the current compilation. + */ + +typedef char + __curl_rule_03__ + [CurlchkszGE(curl_off_t, long)]; + +/* + * Verify that the size previously defined and expected for + * curl_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_04__ + [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of curl_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __curl_rule_05__ + [CurlchkszGE(curl_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +/* + * Get rid of macros private to this header file. + */ + +#undef CurlchkszEQ +#undef CurlchkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CURL_PULL_WS2TCPIP_H +#undef CURL_PULL_SYS_TYPES_H +#undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H +#undef CURL_PULL_STDINT_H +#undef CURL_PULL_INTTYPES_H + +#undef CURL_TYPEOF_CURL_SOCKLEN_T +#undef CURL_TYPEOF_CURL_OFF_T + +#ifdef CURL_NO_OLDIES +#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ +#endif + +#endif /* __CURL_CURLRULES_H */ diff --git a/compat/curl-for-windows/curl/include/curl/curlver.h b/compat/curl-for-windows/curl/include/curl/curlver.h new file mode 100644 index 000000000..7cc268f78 --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/curlver.h @@ -0,0 +1,69 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2014 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.38.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 38 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. +*/ +#define LIBCURL_VERSION_NUM 0x072600 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "Mon Nov 03 12:00:00 UTC 2014" + +#endif /* __CURL_CURLVER_H */ diff --git a/compat/curl-for-windows/curl/include/curl/easy.h b/compat/curl-for-windows/curl/include/curl/easy.h new file mode 100644 index 000000000..c1e3e7609 --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/compat/curl-for-windows/curl/include/curl/mprintf.h b/compat/curl-for-windows/curl/include/curl/mprintf.h new file mode 100644 index 000000000..cc9e7f5d1 --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/mprintf.h @@ -0,0 +1,81 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef _MPRINTF_REPLACE +# undef printf +# undef fprintf +# undef sprintf +# undef vsprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +#ifdef CURLDEBUG +/* When built with CURLDEBUG we define away the sprintf functions since we + don't want internal code to be using them */ +# define sprintf sprintf_was_used +# define vsprintf vsprintf_was_used +#else +# define sprintf curl_msprintf +# define vsprintf curl_mvsprintf +#endif +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/compat/curl-for-windows/curl/include/curl/multi.h b/compat/curl-for-windows/curl/include/curl/multi.h new file mode 100644 index 000000000..3c4acb0f6 --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/multi.h @@ -0,0 +1,399 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURLM; + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/compat/curl-for-windows/curl/include/curl/stdcheaders.h b/compat/curl-for-windows/curl/include/curl/stdcheaders.h new file mode 100644 index 000000000..ad82ef633 --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/compat/curl-for-windows/curl/include/curl/typecheck-gcc.h b/compat/curl-for-windows/curl/include/curl/typecheck-gcc.h new file mode 100644 index 000000000..69d41a20d --- /dev/null +++ b/compat/curl-for-windows/curl/include/curl/typecheck-gcc.h @@ -0,0 +1,610 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__ (option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__ (info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string (char* or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a FILE* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a void* or char* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a struct curl_httppost* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a struct curl_slist* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to char * for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to struct curl_slist * for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_URL || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_WRITEDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + (option) == CURLOPT_MAIL_RCPT || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (CURLINFO_SLIST < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void*)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *)) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func), type*)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*); +typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*); +typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/compat/curl-for-windows/openssl/config/opensslconf.h b/compat/curl-for-windows/openssl/config/opensslconf.h new file mode 100644 index 000000000..9bf23692d --- /dev/null +++ b/compat/curl-for-windows/openssl/config/opensslconf.h @@ -0,0 +1,333 @@ +/* opensslconf.h */ +/* WARNING: Generated automatically from opensslconf.h.in by Configure. */ + +/* OpenSSL was configured with the following options: */ +#undef OPENSSL_SYSNAME_WIN32 +#if defined(_WIN32) +# define OPENSSL_SYSNAME_WIN32 +#endif + +#ifndef OPENSSL_DOING_MAKEDEPEND +# ifndef OPENSSL_NO_CAPIENG +# define OPENSSL_NO_CAPIENG +# endif +# ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +# endif +# ifndef OPENSSL_NO_GMP +# define OPENSSL_NO_GMP +# endif +# ifndef OPENSSL_NO_GOST +# define OPENSSL_NO_GOST +# endif +# ifndef OPENSSL_NO_HW_PADLOCK +# define OPENSSL_NO_HW_PADLOCK +# endif +# ifndef OPENSSL_NO_JPAKE +# define OPENSSL_NO_JPAKE +# endif +# ifndef OPENSSL_NO_KRB5 +# define OPENSSL_NO_KRB5 +# endif +# ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +# endif +# ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +# endif +# ifndef OPENSSL_NO_RFC3779 +# define OPENSSL_NO_RFC3779 +# endif +# ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +# endif +# ifndef OPENSSL_NO_STORE +# define OPENSSL_NO_STORE +# endif +#endif /* OPENSSL_DOING_MAKEDEPEND */ + +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_DYNAMIC_ENGINE +# define OPENSSL_NO_DYNAMIC_ENGINE +#endif + +/* The OPENSSL_NO_* macros are also defined as NO_* if the application + asks for it. This is a transient feature that is provided for those + who haven't had the time to do the appropriate changes in their + applications. */ +#ifdef OPENSSL_ALGORITHM_DEFINES +# if defined(OPENSSL_NO_CAMELLIA) && !defined(NO_CAMELLIA) +# define NO_CAMELLIA +# endif +# if defined(OPENSSL_NO_CAPIENG) && !defined(NO_CAPIENG) +# define NO_CAPIENG +# endif +# if defined(OPENSSL_NO_CAST) && !defined(NO_CAST) +# define NO_CAST +# endif +# if defined(OPENSSL_NO_CMS) && !defined(NO_CMS) +# define NO_CMS +# endif +# if defined(OPENSSL_NO_FIPS) && !defined(NO_FIPS) +# define NO_FIPS +# endif +# if defined(OPENSSL_NO_GMP) && !defined(NO_GMP) +# define NO_GMP +# endif +# if defined(OPENSSL_NO_IDEA) && !defined(NO_IDEA) +# define NO_IDEA +# endif +# if defined(OPENSSL_NO_JPAKE) && !defined(NO_JPAKE) +# define NO_JPAKE +# endif +# if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5) +# define NO_KRB5 +# endif +# if defined(OPENSSL_NO_MD2) && !defined(NO_MD2) +# define NO_MD2 +# endif +# if defined(OPENSSL_NO_MDC2) && !defined(NO_MDC2) +# define NO_MDC2 +# endif +# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5) +# define NO_RC5 +# endif +# if defined(OPENSSL_NO_RFC3779) && !defined(NO_RFC3779) +# define NO_RFC3779 +# endif +# if defined(OPENSSL_NO_SEED) && !defined(NO_SEED) +# define NO_SEED +# endif +# if defined(OPENSSL_NO_SHA0) && !defined(NO_SHA0) +# define NO_SHA0 +# endif +# if defined(OPENSSL_NO_STORE) && !defined(NO_STORE) +# define NO_STORE +# endif +# if defined(OPENSSL_NO_WHRLPOOL) && !defined(NO_WHRLPOOL) +# define NO_WHRLPOOL +# endif +# if defined(OPENSSL_NO_MDC2) && !defined(NO_MDC2) +# define NO_MDC2 +# endif +#endif + +/* crypto/opensslconf.h.in */ + +#ifdef OPENSSL_DOING_MAKEDEPEND + /* Include any symbols here that have to be explicitly set to enable a feature + * that should be visible to makedepend. + * + * [Our "make depend" doesn't actually look at this, we use actual build settings + * instead; we want to make it easy to remove subdirectories with disabled algorithms.] + */ +# ifndef OPENSSL_FIPS +# define OPENSSL_FIPS +# endif +#endif + +/* Generate 80386 code? */ +#undef I386_ONLY + +#if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */ +# if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR) +# if defined(_WIN32) +# define ENGINESDIR "ssl/lib/engines" +# define OPENSSLDIR "ssl" +# else +# define ENGINESDIR "/usr/local/ssl/lib/engines" +# define OPENSSLDIR "/usr/local/ssl" +# endif +# endif +#endif + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD +#if !defined(_WIN32) && !defined(__arm__) && !defined(__mips__) && !defined(SWIG) +# include +#endif + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION +#if defined(_WIN32) +# define OPENSSL_EXPORT_VAR_AS_FUNCTION +#endif + +#if defined(HEADER_IDEA_H) +# undef IDEA_INT +# define IDEA_INT unsigned int +#endif + +#if defined(HEADER_MD2_H) +# undef MD2_INT +# define MD2_INT unsigned int +#endif + +#if defined(HEADER_RC2_H) +/* I need to put in a mod for the alpha - eay */ +# undef RC2_INT +# define RC2_INT unsigned int +#endif + +#if defined(HEADER_RC4_H) + /* using int types make the structure larger but make the code faster + * on most boxes I have tested - up to %20 faster. */ + /* + * I don't know what does "most" mean, but declaring "int" is a must on: + * - Intel P6 because partial register stalls are very expensive; + * - elder Alpha because it lacks byte load/store instructions; + */ +# undef RC4_INT +# if defined(__arm__) +# define RC4_INT unsigned char +# else +# define RC4_INT unsigned int +# endif + + /* + * This enables code handling data aligned at natural CPU word + * boundary. See crypto/rc4/rc4_enc.c for further details. + */ +# undef RC4_CHUNK +# if (defined(_M_X64) || defined(__x86_64__)) && defined(_WIN32) +# define RC4_CHUNK unsigned long long +# elif (defined(_M_X64) || defined(__x86_64__)) && !defined(_WIN32) +# define RC4_CHUNK unsigned long +# elif defined(__arm__) +# define RC4_CHUNK unsigned long +# else + /* On x86 RC4_CHUNK is not defined */ +# endif +#endif + +#if defined(HEADER_NEW_DES_H) || defined(HEADER_DES_H) + /* If this is set to 'unsigned int' on a DEC Alpha, this gives about a + * %20 speed up (longs are 8 bytes, int's are 4). */ +# undef DES_LONG +# if defined(_M_X64) || defined(__x86_64__) || defined(__arm__) || defined(__mips__) +# define DES_LONG unsigned int +# elif defined(_M_IX86) || defined(__i386__) +# define DES_LONG unsigned long +# endif +#endif + +#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H) +# define CONFIG_HEADER_BN_H + +# undef BL_LLONG +# if defined(_M_IX86) || defined(__i386__) || defined(__arm__) +# define BL_LLONG +# endif + + /* Should we define BN_DIV2W here? */ + + /* Only one for the following should be defined */ + /* The prime number generation stuff may not work when + * EIGHT_BIT but I don't care since I've only used this mode + * for debuging the bignum libraries */ +# undef SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# undef THIRTY_TWO_BIT +# undef SIXTEEN_BIT +# undef EIGHT_BIT +# if (defined(_M_X64) || defined(__x86_64__)) && defined(_WIN32) +# define SIXTY_FOUR_BIT +# elif (defined(_M_X64) || defined(__x86_64__)) && !defined(_WIN32) +# define SIXTY_FOUR_BIT_LONG +# elif defined(_M_IX86) || defined(__i386__) || defined(__arm__) || defined(__mips__) +# define THIRTY_TWO_BIT +# endif +#endif + +#if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H) +# define CONFIG_HEADER_RC4_LOCL_H + /* if this is defined data[i] is used instead of *data, this is a %20 + * speedup on x86 */ +# undef RC4_INDEX +# if defined(_M_IX86) || defined(__i386__) +# define RC4_INDEX +# endif +#endif + +#if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H) +# define CONFIG_HEADER_BF_LOCL_H +# undef BF_PTR +# if defined(__arm__) +# define BF_PTR +# endif +#endif /* HEADER_BF_LOCL_H */ + +#if defined(HEADER_DES_LOCL_H) && !defined(CONFIG_HEADER_DES_LOCL_H) +# define CONFIG_HEADER_DES_LOCL_H + +# ifndef DES_DEFAULT_OPTIONS + /* the following is tweaked from a config script, that is why it is a + * protected undef/define */ +# undef DES_PTR +# if !defined(_WIN32) && (defined(_M_IX86) || defined(__i386__)) +# define DES_PTR +# endif + + /* This helps C compiler generate the correct code for multiple functional + * units. It reduces register dependancies at the expense of 2 more + * registers */ +# undef DES_RISC1 +# if !defined(_WIN32) && (defined(_M_IX86) || defined(__i386__)) +# define DES_RISC1 +# endif + +# undef DES_RISC2 + +# if defined(DES_RISC1) && defined(DES_RISC2) +# error YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!! +# endif + + /* Unroll the inner loop, this sometimes helps, sometimes hinders. + * Very mucy CPU dependant */ +# undef DES_UNROLL +# if !defined(_WIN32) +# define DES_UNROLL +# endif + + /* These default values were supplied by + * Peter Gutman + * They are only used if nothing else has been defined */ +# if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL) + /* Special defines which change the way the code is built depending on the + CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find + even newer MIPS CPU's, but at the moment one size fits all for + optimization options. Older Sparc's work better with only UNROLL, but + there's no way to tell at compile time what it is you're running on */ +# if defined( sun ) /* Newer Sparc's */ +# define DES_PTR +# define DES_RISC1 +# define DES_UNROLL +# elif defined( __ultrix ) /* Older MIPS */ +# define DES_PTR +# define DES_RISC2 +# define DES_UNROLL +# elif defined( __osf1__ ) /* Alpha */ +# define DES_PTR +# define DES_RISC2 +# elif defined ( _AIX ) /* RS6000 */ + /* Unknown */ +# elif defined( __hpux ) /* HP-PA */ + /* Unknown */ +# elif defined( __aux ) /* 68K */ + /* Unknown */ +# elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ +# define DES_UNROLL +# elif defined( __sgi ) /* Newer MIPS */ +# define DES_PTR +# define DES_RISC2 +# define DES_UNROLL +# elif defined(i386) || defined(__i386__) /* x86 boxes, should be gcc */ +# define DES_PTR +# define DES_RISC1 +# define DES_UNROLL +# endif /* Systems-specific speed defines */ +# endif + +# endif /* DES_DEFAULT_OPTIONS */ +#endif /* HEADER_DES_LOCL_H */ diff --git a/compat/curl-for-windows/openssl/openssl/crypto/opensslconf.h b/compat/curl-for-windows/openssl/openssl/crypto/opensslconf.h new file mode 100644 index 000000000..76c99d433 --- /dev/null +++ b/compat/curl-for-windows/openssl/openssl/crypto/opensslconf.h @@ -0,0 +1 @@ +#include "../../config/opensslconf.h" diff --git a/compat/curl-for-windows/openssl/openssl/crypto/sha/sha.h b/compat/curl-for-windows/openssl/openssl/crypto/sha/sha.h new file mode 100644 index 000000000..8a6bf4bbb --- /dev/null +++ b/compat/curl-for-windows/openssl/openssl/crypto/sha/sha.h @@ -0,0 +1,214 @@ +/* crypto/sha/sha.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_SHA_H +#define HEADER_SHA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1)) +#error SHA is disabled. +#endif + +#if defined(OPENSSL_FIPS) +#define FIPS_SHA_SIZE_T size_t +#endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! SHA_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(__LP32__) +#define SHA_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define SHA_LONG unsigned long +#define SHA_LONG_LOG2 3 +#else +#define SHA_LONG unsigned int +#endif + +#define SHA_LBLOCK 16 +#define SHA_CBLOCK (SHA_LBLOCK*4) /* SHA treats input data as a + * contiguous array of 32 bit + * wide big-endian values. */ +#define SHA_LAST_BLOCK (SHA_CBLOCK-8) +#define SHA_DIGEST_LENGTH 20 + +typedef struct SHAstate_st + { + SHA_LONG h0,h1,h2,h3,h4; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num; + } SHA_CTX; + +#ifndef OPENSSL_NO_SHA0 +#ifdef OPENSSL_FIPS +int private_SHA_Init(SHA_CTX *c); +#endif +int SHA_Init(SHA_CTX *c); +int SHA_Update(SHA_CTX *c, const void *data, size_t len); +int SHA_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA(const unsigned char *d, size_t n, unsigned char *md); +void SHA_Transform(SHA_CTX *c, const unsigned char *data); +#endif +#ifndef OPENSSL_NO_SHA1 +#ifdef OPENSSL_FIPS +int private_SHA1_Init(SHA_CTX *c); +#endif +int SHA1_Init(SHA_CTX *c); +int SHA1_Update(SHA_CTX *c, const void *data, size_t len); +int SHA1_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md); +void SHA1_Transform(SHA_CTX *c, const unsigned char *data); +#endif + +#define SHA256_CBLOCK (SHA_LBLOCK*4) /* SHA-256 treats input data as a + * contiguous array of 32 bit + * wide big-endian values. */ +#define SHA224_DIGEST_LENGTH 28 +#define SHA256_DIGEST_LENGTH 32 + +typedef struct SHA256state_st + { + SHA_LONG h[8]; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num,md_len; + } SHA256_CTX; + +#ifndef OPENSSL_NO_SHA256 +#ifdef OPENSSL_FIPS +int private_SHA224_Init(SHA256_CTX *c); +int private_SHA256_Init(SHA256_CTX *c); +#endif +int SHA224_Init(SHA256_CTX *c); +int SHA224_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA224_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA224(const unsigned char *d, size_t n,unsigned char *md); +int SHA256_Init(SHA256_CTX *c); +int SHA256_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA256_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA256(const unsigned char *d, size_t n,unsigned char *md); +void SHA256_Transform(SHA256_CTX *c, const unsigned char *data); +#endif + +#define SHA384_DIGEST_LENGTH 48 +#define SHA512_DIGEST_LENGTH 64 + +#ifndef OPENSSL_NO_SHA512 +/* + * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64 + * being exactly 64-bit wide. See Implementation Notes in sha512.c + * for further details. + */ +#define SHA512_CBLOCK (SHA_LBLOCK*8) /* SHA-512 treats input data as a + * contiguous array of 64 bit + * wide big-endian values. */ +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +#define SHA_LONG64 unsigned __int64 +#define U64(C) C##UI64 +#elif defined(__arch64__) +#define SHA_LONG64 unsigned long +#define U64(C) C##UL +#else +#define SHA_LONG64 unsigned long long +#define U64(C) C##ULL +#endif + +typedef struct SHA512state_st + { + SHA_LONG64 h[8]; + SHA_LONG64 Nl,Nh; + union { + SHA_LONG64 d[SHA_LBLOCK]; + unsigned char p[SHA512_CBLOCK]; + } u; + unsigned int num,md_len; + } SHA512_CTX; +#endif + +#ifndef OPENSSL_NO_SHA512 +#ifdef OPENSSL_FIPS +int private_SHA384_Init(SHA512_CTX *c); +int private_SHA512_Init(SHA512_CTX *c); +#endif +int SHA384_Init(SHA512_CTX *c); +int SHA384_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA384_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA384(const unsigned char *d, size_t n,unsigned char *md); +int SHA512_Init(SHA512_CTX *c); +int SHA512_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA512_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA512(const unsigned char *d, size_t n,unsigned char *md); +void SHA512_Transform(SHA512_CTX *c, const unsigned char *data); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/compat/curl-for-windows/openssl/openssl/e_os2.h b/compat/curl-for-windows/openssl/openssl/e_os2.h new file mode 100644 index 000000000..d22c0368f --- /dev/null +++ b/compat/curl-for-windows/openssl/openssl/e_os2.h @@ -0,0 +1,315 @@ +/* e_os2.h */ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#ifndef HEADER_E_OS2_H +#define HEADER_E_OS2_H + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Detect operating systems. This probably needs completing. + * The result is that at least one OPENSSL_SYS_os macro should be defined. + * However, if none is defined, Unix is assumed. + **/ + +#define OPENSSL_SYS_UNIX + +/* ----------------------- Macintosh, before MacOS X ----------------------- */ +#if defined(__MWERKS__) && defined(macintosh) || defined(OPENSSL_SYSNAME_MAC) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_MACINTOSH_CLASSIC +#endif + +/* ----------------------- NetWare ----------------------------------------- */ +#if defined(NETWARE) || defined(OPENSSL_SYSNAME_NETWARE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_NETWARE +#endif + +/* ---------------------- Microsoft operating systems ---------------------- */ + +/* Note that MSDOS actually denotes 32-bit environments running on top of + MS-DOS, such as DJGPP one. */ +#if defined(OPENSSL_SYSNAME_MSDOS) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_MSDOS +#endif + +/* For 32 bit environment, there seems to be the CygWin environment and then + all the others that try to do the same thing Microsoft does... */ +#if defined(OPENSSL_SYSNAME_UWIN) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32_UWIN +#else +# if defined(__CYGWIN32__) || defined(OPENSSL_SYSNAME_CYGWIN32) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32_CYGWIN +# else +# if defined(_WIN32) || defined(OPENSSL_SYSNAME_WIN32) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32 +# endif +# if defined(OPENSSL_SYSNAME_WINNT) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINNT +# endif +# if defined(OPENSSL_SYSNAME_WINCE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINCE +# endif +# endif +#endif + +/* Anything that tries to look like Microsoft is "Windows" */ +#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINNT) || defined(OPENSSL_SYS_WINCE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINDOWS +# ifndef OPENSSL_SYS_MSDOS +# define OPENSSL_SYS_MSDOS +# endif +#endif + +/* DLL settings. This part is a bit tough, because it's up to the application + implementor how he or she will link the application, so it requires some + macro to be used. */ +#ifdef OPENSSL_SYS_WINDOWS +# ifndef OPENSSL_OPT_WINDLL +# if defined(_WINDLL) /* This is used when building OpenSSL to indicate that + DLL linkage should be used */ +# define OPENSSL_OPT_WINDLL +# endif +# endif +#endif + +/* -------------------------------- OpenVMS -------------------------------- */ +#if defined(__VMS) || defined(VMS) || defined(OPENSSL_SYSNAME_VMS) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_VMS +# if defined(__DECC) +# define OPENSSL_SYS_VMS_DECC +# elif defined(__DECCXX) +# define OPENSSL_SYS_VMS_DECC +# define OPENSSL_SYS_VMS_DECCXX +# else +# define OPENSSL_SYS_VMS_NODECC +# endif +#endif + +/* --------------------------------- OS/2 ---------------------------------- */ +#if defined(__EMX__) || defined(__OS2__) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_OS2 +#endif + +/* --------------------------------- Unix ---------------------------------- */ +#ifdef OPENSSL_SYS_UNIX +# if defined(linux) || defined(__linux__) || defined(OPENSSL_SYSNAME_LINUX) +# define OPENSSL_SYS_LINUX +# endif +# ifdef OPENSSL_SYSNAME_MPE +# define OPENSSL_SYS_MPE +# endif +# ifdef OPENSSL_SYSNAME_SNI +# define OPENSSL_SYS_SNI +# endif +# ifdef OPENSSL_SYSNAME_ULTRASPARC +# define OPENSSL_SYS_ULTRASPARC +# endif +# ifdef OPENSSL_SYSNAME_NEWS4 +# define OPENSSL_SYS_NEWS4 +# endif +# ifdef OPENSSL_SYSNAME_MACOSX +# define OPENSSL_SYS_MACOSX +# endif +# ifdef OPENSSL_SYSNAME_MACOSX_RHAPSODY +# define OPENSSL_SYS_MACOSX_RHAPSODY +# define OPENSSL_SYS_MACOSX +# endif +# ifdef OPENSSL_SYSNAME_SUNOS +# define OPENSSL_SYS_SUNOS +#endif +# if defined(_CRAY) || defined(OPENSSL_SYSNAME_CRAY) +# define OPENSSL_SYS_CRAY +# endif +# if defined(_AIX) || defined(OPENSSL_SYSNAME_AIX) +# define OPENSSL_SYS_AIX +# endif +#endif + +/* --------------------------------- VOS ----------------------------------- */ +#if defined(__VOS__) || defined(OPENSSL_SYSNAME_VOS) +# define OPENSSL_SYS_VOS +#ifdef __HPPA__ +# define OPENSSL_SYS_VOS_HPPA +#endif +#ifdef __IA32__ +# define OPENSSL_SYS_VOS_IA32 +#endif +#endif + +/* ------------------------------- VxWorks --------------------------------- */ +#ifdef OPENSSL_SYSNAME_VXWORKS +# define OPENSSL_SYS_VXWORKS +#endif + +/* --------------------------------- BeOS ---------------------------------- */ +#if defined(__BEOS__) +# define OPENSSL_SYS_BEOS +# include +# if defined(BONE_VERSION) +# define OPENSSL_SYS_BEOS_BONE +# else +# define OPENSSL_SYS_BEOS_R5 +# endif +#endif + +/** + * That's it for OS-specific stuff + *****************************************************************************/ + + +/* Specials for I/O an exit */ +#ifdef OPENSSL_SYS_MSDOS +# define OPENSSL_UNISTD_IO +# define OPENSSL_DECLARE_EXIT extern void exit(int); +#else +# define OPENSSL_UNISTD_IO OPENSSL_UNISTD +# define OPENSSL_DECLARE_EXIT /* declared in unistd.h */ +#endif + +/* Definitions of OPENSSL_GLOBAL and OPENSSL_EXTERN, to define and declare + certain global symbols that, with some compilers under VMS, have to be + defined and declared explicitely with globaldef and globalref. + Definitions of OPENSSL_EXPORT and OPENSSL_IMPORT, to define and declare + DLL exports and imports for compilers under Win32. These are a little + more complicated to use. Basically, for any library that exports some + global variables, the following code must be present in the header file + that declares them, before OPENSSL_EXTERN is used: + + #ifdef SOME_BUILD_FLAG_MACRO + # undef OPENSSL_EXTERN + # define OPENSSL_EXTERN OPENSSL_EXPORT + #endif + + The default is to have OPENSSL_EXPORT, OPENSSL_IMPORT and OPENSSL_GLOBAL + have some generally sensible values, and for OPENSSL_EXTERN to have the + value OPENSSL_IMPORT. +*/ + +#if defined(OPENSSL_SYS_VMS_NODECC) +# define OPENSSL_EXPORT globalref +# define OPENSSL_IMPORT globalref +# define OPENSSL_GLOBAL globaldef +#elif defined(OPENSSL_SYS_WINDOWS) && defined(OPENSSL_OPT_WINDLL) +# define OPENSSL_EXPORT extern __declspec(dllexport) +# define OPENSSL_IMPORT extern __declspec(dllimport) +# define OPENSSL_GLOBAL +#else +# define OPENSSL_EXPORT extern +# define OPENSSL_IMPORT extern +# define OPENSSL_GLOBAL +#endif +#define OPENSSL_EXTERN OPENSSL_IMPORT + +/* Macros to allow global variables to be reached through function calls when + required (if a shared library version requires it, for example. + The way it's done allows definitions like this: + + // in foobar.c + OPENSSL_IMPLEMENT_GLOBAL(int,foobar,0) + // in foobar.h + OPENSSL_DECLARE_GLOBAL(int,foobar); + #define foobar OPENSSL_GLOBAL_REF(foobar) +*/ +#ifdef OPENSSL_EXPORT_VAR_AS_FUNCTION +# define OPENSSL_IMPLEMENT_GLOBAL(type,name,value) \ + type *_shadow_##name(void) \ + { static type _hide_##name=value; return &_hide_##name; } +# define OPENSSL_DECLARE_GLOBAL(type,name) type *_shadow_##name(void) +# define OPENSSL_GLOBAL_REF(name) (*(_shadow_##name())) +#else +# define OPENSSL_IMPLEMENT_GLOBAL(type,name,value) OPENSSL_GLOBAL type _shadow_##name=value; +# define OPENSSL_DECLARE_GLOBAL(type,name) OPENSSL_EXPORT type _shadow_##name +# define OPENSSL_GLOBAL_REF(name) _shadow_##name +#endif + +#if defined(OPENSSL_SYS_MACINTOSH_CLASSIC) && macintosh==1 && !defined(MAC_OS_GUSI_SOURCE) +# define ossl_ssize_t long +#endif + +#ifdef OPENSSL_SYS_MSDOS +# define ossl_ssize_t long +#endif + +#if defined(NeXT) || defined(OPENSSL_SYS_NEWS4) || defined(OPENSSL_SYS_SUNOS) +# define ssize_t int +#endif + +#if defined(__ultrix) && !defined(ssize_t) +# define ossl_ssize_t int +#endif + +#ifndef ossl_ssize_t +# define ossl_ssize_t ssize_t +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/compat/curl-for-windows/openssl/openssl/include/openssl/e_os2.h b/compat/curl-for-windows/openssl/openssl/include/openssl/e_os2.h new file mode 100644 index 000000000..ab3f1ee44 --- /dev/null +++ b/compat/curl-for-windows/openssl/openssl/include/openssl/e_os2.h @@ -0,0 +1 @@ +#include "../../e_os2.h" diff --git a/compat/curl-for-windows/openssl/openssl/include/openssl/opensslconf.h b/compat/curl-for-windows/openssl/openssl/include/openssl/opensslconf.h new file mode 100644 index 000000000..221be629b --- /dev/null +++ b/compat/curl-for-windows/openssl/openssl/include/openssl/opensslconf.h @@ -0,0 +1 @@ +#include "../../crypto/opensslconf.h" diff --git a/compat/curl-for-windows/openssl/openssl/include/openssl/sha.h b/compat/curl-for-windows/openssl/openssl/include/openssl/sha.h new file mode 100644 index 000000000..ab9d94c38 --- /dev/null +++ b/compat/curl-for-windows/openssl/openssl/include/openssl/sha.h @@ -0,0 +1 @@ +#include "../../crypto/sha/sha.h" diff --git a/compat/curl-for-windows/out/x64/Release/lib/libcurl.x64.lib b/compat/curl-for-windows/out/x64/Release/lib/libcurl.x64.lib new file mode 100644 index 000000000..d6f6a7a29 Binary files /dev/null and b/compat/curl-for-windows/out/x64/Release/lib/libcurl.x64.lib differ diff --git a/compat/curl-for-windows/out/x64/Release/lib/openssl.x64.lib b/compat/curl-for-windows/out/x64/Release/lib/openssl.x64.lib new file mode 100644 index 000000000..dd91ed833 Binary files /dev/null and b/compat/curl-for-windows/out/x64/Release/lib/openssl.x64.lib differ diff --git a/compat/curl-for-windows/out/x64/Release/lib/zlib.x64.lib b/compat/curl-for-windows/out/x64/Release/lib/zlib.x64.lib new file mode 100644 index 000000000..7425525c9 Binary files /dev/null and b/compat/curl-for-windows/out/x64/Release/lib/zlib.x64.lib differ diff --git a/compat/curl-for-windows/zlib/zconf.h b/compat/curl-for-windows/zlib/zconf.h new file mode 100644 index 000000000..9987a7755 --- /dev/null +++ b/compat/curl-for-windows/zlib/zconf.h @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/compat/curl-for-windows/zlib/zlib.h b/compat/curl-for-windows/zlib/zlib.h new file mode 100644 index 000000000..3e0c7672a --- /dev/null +++ b/compat/curl-for-windows/zlib/zlib.h @@ -0,0 +1,1768 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 8 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/compat/getopt/getopt.h b/compat/getopt/getopt.h new file mode 100644 index 000000000..4de6e853e --- /dev/null +++ b/compat/getopt/getopt.h @@ -0,0 +1,93 @@ +/* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */ +/* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#if 0 +#include +#endif + +/* + * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int getopt_long(int, char * const *, const char *, + const struct option *, int *); +int getopt_long_only(int, char * const *, const char *, + const struct option *, int *); +#ifndef _GETOPT_DEFINED +#define _GETOPT_DEFINED +int getopt(int, char * const *, const char *); +int getsubopt(char **, char * const *, char **); + +extern char *optarg; /* getopt(3) external variables */ +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *suboptarg; /* getsubopt(3) external variable */ +#endif /* _GETOPT_DEFINED */ + +#ifdef __cplusplus +} +#endif +#endif /* !_GETOPT_H_ */ diff --git a/compat/getopt/getopt_long.c b/compat/getopt/getopt_long.c new file mode 100644 index 000000000..66d01bd0a --- /dev/null +++ b/compat/getopt/getopt_long.c @@ -0,0 +1,554 @@ +/* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */ +/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ + +/* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#ifndef lint +static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $"; +#endif /* lint */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if 0 +#include +#endif +#include +#include +#include +#include + +#ifdef _WIN32 + +/* Windows needs warnx(). We change the definition though: + * 1. (another) global is defined, opterrmsg, which holds the error message + * 2. errors are always printed out on stderr w/o the program name + * Note that opterrmsg always gets set no matter what opterr is set to. The + * error message will not be printed if opterr is 0 as usual. + */ + +#include +#include +#include + +char opterrmsg[128]; /* last error message is stored here */ + +static void warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (fmt != NULL) + _vsnprintf(opterrmsg, 128, fmt, ap); + else + opterrmsg[0]='\0'; + va_end(ap); + fprintf(stderr, opterrmsg); + fprintf(stderr, "\n"); +} + +#endif /*_WIN32*/ + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} diff --git a/compat/gettimeofday.c b/compat/gettimeofday.c new file mode 100644 index 000000000..220856be9 --- /dev/null +++ b/compat/gettimeofday.c @@ -0,0 +1,83 @@ +#include < time.h > +#include //I've ommited this line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres /= 10; /*convert into microseconds*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} + +void usleep(__int64 waitTime) +{ + if (waitTime > 0) + { + if (waitTime > 100) + { + // use a waitable timer for larger intervals > 0.1ms + + HANDLE timer; + LARGE_INTEGER ft; + + ft.QuadPart = -(10*waitTime); // Convert to 100 nanosecond interval, negative value indicates relative time + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); + } + else + { + // use a polling loop for short intervals <= 100ms + + LARGE_INTEGER perfCnt, start, now; + __int64 elapsed; + + QueryPerformanceFrequency(&perfCnt); + QueryPerformanceCounter(&start); + do { + QueryPerformanceCounter((LARGE_INTEGER*) &now); + elapsed = (__int64)((now.QuadPart - start.QuadPart) / (float)perfCnt.QuadPart * 1000 * 1000); + } while ( elapsed < waitTime ); + } + } +} diff --git a/compat/inttypes.h b/compat/inttypes.h new file mode 100644 index 000000000..dc7485e48 --- /dev/null +++ b/compat/inttypes.h @@ -0,0 +1,2 @@ +#pragma once +#include diff --git a/compat/jansson/.gitignore b/compat/jansson/.gitignore index 173737b67..55344a1e6 100644 --- a/compat/jansson/.gitignore +++ b/compat/jansson/.gitignore @@ -1,3 +1,4 @@ - +*.h.in +*.h.in~ +libtool libjansson.a - diff --git a/compat/jansson/Makefile.am b/compat/jansson/Makefile.am index 94a583f34..e27f05af7 100644 --- a/compat/jansson/Makefile.am +++ b/compat/jansson/Makefile.am @@ -1,18 +1,20 @@ -noinst_LIBRARIES = libjansson.a +noinst_LIBRARIES = libjansson.a -libjansson_a_SOURCES = \ - config.h \ - dump.c \ - hashtable.c \ - hashtable.h \ - jansson.h \ - jansson_private.h \ - load.c \ - strbuffer.c \ - strbuffer.h \ - utf.c \ - utf.h \ - util.h \ - value.c +libjansson_a_SOURCES = \ + config.h \ + dump.c \ + error.c \ + hashtable.c hashtable.h \ + jansson.h \ + jansson_config.h \ + jansson_private.h \ + load.c \ + memory.c \ + pack_unpack.c \ + strbuffer.c strbuffer.h \ + strconv.c \ + utf.c utf.h \ + util.h \ + value.c diff --git a/compat/jansson/config.h b/compat/jansson/config.h index 43858aa61..bbc54b977 100644 --- a/compat/jansson/config.h +++ b/compat/jansson/config.h @@ -1,15 +1,54 @@ /* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Define to 1 if gcc's __atomic builtins are available */ +/* #undef HAVE_ATOMIC_BUILTINS */ + +/* Define to 1 if you have the `close' function. */ +#define HAVE_CLOSE 1 + /* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 +/* Define to 1 if you have the `localeconv' function. */ +#define HAVE_LOCALECONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if the system has the type `long long int'. */ +#define HAVE_LONG_LONG_INT 1 + /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 +/* Define to 1 if you have the `open' function. */ +#define HAVE_OPEN 1 + +/* Define to 1 if you have the `read' function. */ +#define HAVE_READ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define to 1 if you have the `sched_yield' function. */ +/* #undef HAVE_SCHED_YIELD */ + /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 @@ -22,9 +61,21 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + +/* Define to 1 if gcc's __sync builtins are available */ +#define HAVE_SYNC_BUILTINS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 @@ -45,7 +96,7 @@ #define PACKAGE_NAME "jansson" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "jansson 1.3" +#define PACKAGE_STRING "jansson 2.6" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "jansson" @@ -54,13 +105,25 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.3" +#define PACKAGE_VERSION "2.6" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 +/* Define to 1 if /dev/urandom should be used for seeding the hash function */ +#define USE_URANDOM 1 + +/* Define to 1 if CryptGenRandom should be used for seeding the hash function + */ +#define USE_WINDOWS_CRYPTOAPI 1 + /* Version number of package */ -#define VERSION "1.3" +#define VERSION "2.6" + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ @@ -71,3 +134,7 @@ /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ /* #undef int32_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ diff --git a/compat/jansson/configure.ac b/compat/jansson/configure.ac new file mode 100644 index 000000000..e7e88a4f3 --- /dev/null +++ b/compat/jansson/configure.ac @@ -0,0 +1,98 @@ +AC_PREREQ([2.60]) +AC_INIT([jansson], [2.6], [petri@digip.org]) + +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.10 foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_CONFIG_SRCDIR([value.c]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AM_CONDITIONAL([GCC], [test x$GCC = xyes]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_UINT32_T +AC_TYPE_LONG_LONG_INT + +AC_C_INLINE +case $ac_cv_c_inline in + yes) json_inline=inline;; + no) json_inline=;; + *) json_inline=$ac_cv_c_inline;; +esac +AC_SUBST([json_inline]) + +# Checks for library functions. +AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll]) + +AC_MSG_CHECKING([for gcc __sync builtins]) +have_sync_builtins=no +AC_TRY_LINK( + [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1);], + [have_sync_builtins=yes], +) +if test "x$have_sync_builtins" = "xyes"; then + AC_DEFINE([HAVE_SYNC_BUILTINS], [1], + [Define to 1 if gcc's __sync builtins are available]) +fi +AC_MSG_RESULT([$have_sync_builtins]) + +AC_MSG_CHECKING([for gcc __atomic builtins]) +have_atomic_builtins=no +AC_TRY_LINK( + [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_ACQ_REL); __atomic_load_n(&v, __ATOMIC_ACQUIRE);], + [have_atomic_builtins=yes], +) +if test "x$have_atomic_builtins" = "xyes"; then + AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], + [Define to 1 if gcc's __atomic builtins are available]) +fi +AC_MSG_RESULT([$have_atomic_builtins]) + +case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in + yesyes) json_have_long_long=1;; + *) json_have_long_long=0;; +esac +AC_SUBST([json_have_long_long]) + +case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in + yesyes) json_have_localeconv=1;; + *) json_have_localeconv=0;; +esac +AC_SUBST([json_have_localeconv]) + +# Features +AC_ARG_ENABLE([urandom], + [AS_HELP_STRING([--disable-urandom], + [Don't use /dev/urandom to seed the hash function])], + [use_urandom=$enableval], [use_urandom=yes]) + +if test "x$use_urandom" = xyes; then +AC_DEFINE([USE_URANDOM], [1], + [Define to 1 if /dev/urandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([windows-cryptoapi], + [AS_HELP_STRING([--disable-windows-cryptoapi], + [Don't use CryptGenRandom to seed the hash function])], + [use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes]) + +if test "x$use_windows_cryptoapi" = xyes; then +AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1], + [Define to 1 if CryptGenRandom should be used for seeding the hash function]) +fi + +AC_CONFIG_FILES([ + Makefile +]) +AC_OUTPUT diff --git a/compat/jansson/dump.c b/compat/jansson/dump.c index dc27fbde9..3b19c73be 100644 --- a/compat/jansson/dump.c +++ b/compat/jansson/dump.c @@ -1,17 +1,20 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif + #include #include #include #include -#include +#include "jansson.h" #include "jansson_private.h" #include "strbuffer.h" #include "utf.h" @@ -19,21 +22,17 @@ #define MAX_INTEGER_STR_LENGTH 100 #define MAX_REAL_STR_LENGTH 100 -typedef int (*dump_func)(const char *buffer, int size, void *data); - -struct string -{ - char *buffer; - int length; - int size; +struct object_key { + size_t serial; + const char *key; }; -static int dump_to_strbuffer(const char *buffer, int size, void *data) +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) { return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); } -static int dump_to_file(const char *buffer, int size, void *data) +static int dump_to_file(const char *buffer, size_t size, void *data) { FILE *dest = (FILE *)data; if(fwrite(buffer, size, 1, dest) != 1) @@ -41,10 +40,10 @@ static int dump_to_file(const char *buffer, int size, void *data) return 0; } -/* 256 spaces (the maximum indentation size) */ -static char whitespace[] = " "; +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; -static int dump_indent(unsigned long flags, int depth, int space, dump_func dump, void *data) +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) { if(JSON_INDENT(flags) > 0) { @@ -66,7 +65,7 @@ static int dump_indent(unsigned long flags, int depth, int space, dump_func dump return 0; } -static int dump_string(const char *str, int ascii, dump_func dump, void *data) +static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags) { const char *pos, *end; int32_t codepoint; @@ -91,8 +90,12 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) break; + /* slash */ + if((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + /* non-ASCII */ - if(ascii && codepoint > 0x7F) + if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) break; pos = end; @@ -106,7 +109,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) if(end == pos) break; - /* handle \, ", and control codes */ + /* handle \, /, ", and control codes */ length = 2; switch(codepoint) { @@ -117,6 +120,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) case '\n': text = "\\n"; break; case '\r': text = "\\r"; break; case '\t': text = "\\t"; break; + case '/': text = "\\/"; break; default: { /* codepoint is in BMP */ @@ -155,20 +159,23 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) static int object_key_compare_keys(const void *key1, const void *key2) { - return strcmp((*(const object_key_t **)key1)->key, - (*(const object_key_t **)key2)->key); + return strcmp(((const struct object_key *)key1)->key, + ((const struct object_key *)key2)->key); } static int object_key_compare_serials(const void *key1, const void *key2) { - return (*(const object_key_t **)key1)->serial - - (*(const object_key_t **)key2)->serial; + size_t a = ((const struct object_key *)key1)->serial; + size_t b = ((const struct object_key *)key2)->serial; + + return a < b ? -1 : a == b ? 0 : 1; } -static int do_dump(const json_t *json, unsigned long flags, int depth, - dump_func dump, void *data) +static int do_dump(const json_t *json, size_t flags, int depth, + json_dump_callback_t dump, void *data) { - int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0; + if(!json) + return -1; switch(json_typeof(json)) { case JSON_NULL: @@ -185,8 +192,10 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, char buffer[MAX_INTEGER_STR_LENGTH]; int size; - size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%d", json_integer_value(json)); - if(size >= MAX_INTEGER_STR_LENGTH) + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, + "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) return -1; return dump(buffer, size, data); @@ -196,31 +205,17 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, { char buffer[MAX_REAL_STR_LENGTH]; int size; + double value = json_real_value(json); - size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%.17g", - json_real_value(json)); - if(size >= MAX_REAL_STR_LENGTH) + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value); + if(size < 0) return -1; - /* Make sure there's a dot or 'e' in the output. Otherwise - a real is converted to an integer when decoding */ - if(strchr(buffer, '.') == NULL && - strchr(buffer, 'e') == NULL) - { - if(size + 2 >= MAX_REAL_STR_LENGTH) { - /* No space to append ".0" */ - return -1; - } - buffer[size] = '.'; - buffer[size + 1] = '0'; - size += 2; - } - return dump(buffer, size, data); } case JSON_STRING: - return dump_string(json_string_value(json), ascii, dump, data); + return dump_string(json_string_value(json), dump, data, flags); case JSON_ARRAY: { @@ -306,20 +301,20 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) { - const object_key_t **keys; - unsigned int size; - unsigned int i; + struct object_key *keys; + size_t size, i; int (*cmp_func)(const void *, const void *); size = json_object_size(json); - keys = malloc(size * sizeof(object_key_t *)); + keys = jsonp_malloc(size * sizeof(struct object_key)); if(!keys) goto object_error; i = 0; while(iter) { - keys[i] = jsonp_object_iter_fullkey(iter); + keys[i].serial = hashtable_iter_serial(iter); + keys[i].key = json_object_iter_key(iter); iter = json_object_iter_next((json_t *)json, iter); i++; } @@ -330,22 +325,22 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, else cmp_func = object_key_compare_serials; - qsort(keys, size, sizeof(object_key_t *), cmp_func); + qsort(keys, size, sizeof(struct object_key), cmp_func); for(i = 0; i < size; i++) { const char *key; json_t *value; - key = keys[i]->key; + key = keys[i].key; value = json_object_get(json, key); assert(value); - dump_string(key, ascii, dump, data); + dump_string(key, dump, data, flags); if(dump(separator, separator_length, data) || do_dump(value, flags, depth + 1, dump, data)) { - free(keys); + jsonp_free(keys); goto object_error; } @@ -354,7 +349,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, if(dump(",", 1, data) || dump_indent(flags, depth + 1, 1, dump, data)) { - free(keys); + jsonp_free(keys); goto object_error; } } @@ -362,13 +357,13 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, { if(dump_indent(flags, depth, 0, dump, data)) { - free(keys); + jsonp_free(keys); goto object_error; } } } - free(keys); + jsonp_free(keys); } else { @@ -378,7 +373,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, { void *next = json_object_iter_next((json_t *)json, iter); - dump_string(json_object_iter_key(iter), ascii, dump, data); + dump_string(json_object_iter_key(iter), dump, data, flags); if(dump(separator, separator_length, data) || do_dump(json_object_iter_value(iter), flags, depth + 1, dump, data)) @@ -414,38 +409,29 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, } } - -char *json_dumps(const json_t *json, unsigned long flags) +char *json_dumps(const json_t *json, size_t flags) { strbuffer_t strbuff; char *result; - if(!json_is_array(json) && !json_is_object(json)) - return NULL; - if(strbuffer_init(&strbuff)) return NULL; - if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff)) { - strbuffer_close(&strbuff); - return NULL; - } + if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); - result = strdup(strbuffer_value(&strbuff)); strbuffer_close(&strbuff); - return result; } -int json_dumpf(const json_t *json, FILE *output, unsigned long flags) +int json_dumpf(const json_t *json, FILE *output, size_t flags) { - if(!json_is_array(json) && !json_is_object(json)) - return -1; - - return do_dump(json, flags, 0, dump_to_file, (void *)output); + return json_dump_callback(json, dump_to_file, (void *)output, flags); } -int json_dump_file(const json_t *json, const char *path, unsigned long flags) +int json_dump_file(const json_t *json, const char *path, size_t flags) { int result; @@ -458,3 +444,13 @@ int json_dump_file(const json_t *json, const char *path, unsigned long flags) fclose(output); return result; } + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) +{ + if(!(flags & JSON_ENCODE_ANY)) { + if(!json_is_array(json) && !json_is_object(json)) + return -1; + } + + return do_dump(json, flags, 0, callback, data); +} diff --git a/compat/jansson/error.c b/compat/jansson/error.c new file mode 100644 index 000000000..a544a59fb --- /dev/null +++ b/compat/jansson/error.c @@ -0,0 +1,63 @@ +#include +#include "jansson_private.h" + +void jsonp_error_init(json_error_t *error, const char *source) +{ + if(error) + { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if(source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) +{ + size_t length; + + if(!error || !source) + return; + + length = strlen(source); + if(length < JSON_ERROR_SOURCE_LENGTH) + strcpy(error->source, source); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + strcpy(error->source, "..."); + strcpy(error->source + 3, source + extra); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap) +{ + if(!error) + return; + + if(error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; +} diff --git a/compat/jansson/hashtable.c b/compat/jansson/hashtable.c index a31204792..5fb04679a 100644 --- a/compat/jansson/hashtable.c +++ b/compat/jansson/hashtable.c @@ -1,31 +1,46 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ -#include - #include +#include +#include /* for JSON_INLINE */ +#include "jansson_private.h" /* for container_of() */ #include "hashtable.h" typedef struct hashtable_list list_t; typedef struct hashtable_pair pair_t; typedef struct hashtable_bucket bucket_t; -#define container_of(ptr_, type_, member_) \ - ((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_)) - #define list_to_pair(list_) container_of(list_, pair_t, list) -static inline void list_init(list_t *list) +/* From http://www.cse.yorku.ca/~oz/hash.html */ +static size_t hash_str(const void *ptr) +{ + const char *str = (const char *)ptr; + + size_t hash = 5381; + size_t c; + + while((c = (size_t)*str)) + { + hash = ((hash << 5) + hash) + c; + str++; + } + + return hash; +} + +static JSON_INLINE void list_init(list_t *list) { list->next = list; list->prev = list; } -static inline void list_insert(list_t *list, list_t *node) +static JSON_INLINE void list_insert(list_t *list, list_t *node) { node->next = list; node->prev = list->prev; @@ -33,13 +48,13 @@ static inline void list_insert(list_t *list, list_t *node) list->prev = node; } -static inline void list_remove(list_t *list) +static JSON_INLINE void list_remove(list_t *list) { list->prev->next = list->next; list->next->prev = list->prev; } -static inline int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) { return bucket->first == &hashtable->list && bucket->first == bucket->last; } @@ -59,22 +74,21 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, } } -static unsigned int primes[] = { +static const size_t primes[] = { 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; -static const unsigned int num_primes = sizeof(primes) / sizeof(unsigned int); -static inline unsigned int num_buckets(hashtable_t *hashtable) +static JSON_INLINE size_t num_buckets(hashtable_t *hashtable) { return primes[hashtable->num_buckets]; } static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, - const void *key, unsigned int hash) + const char *key, size_t hash) { list_t *list; pair_t *pair; @@ -86,7 +100,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, while(1) { pair = list_to_pair(list); - if(pair->hash == hash && hashtable->cmp_keys(pair->key, key)) + if(pair->hash == hash && strcmp(pair->key, key) == 0) return pair; if(list == bucket->last) @@ -100,11 +114,11 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, /* returns 0 on success, -1 if key was not found */ static int hashtable_do_del(hashtable_t *hashtable, - const void *key, unsigned int hash) + const char *key, size_t hash) { pair_t *pair; bucket_t *bucket; - unsigned int index; + size_t index; index = hash % num_buckets(hashtable); bucket = &hashtable->buckets[index]; @@ -123,13 +137,9 @@ static int hashtable_do_del(hashtable_t *hashtable, bucket->last = pair->list.prev; list_remove(&pair->list); + json_decref(pair->value); - if(hashtable->free_key) - hashtable->free_key(pair->key); - if(hashtable->free_value) - hashtable->free_value(pair->value); - - free(pair); + jsonp_free(pair); hashtable->size--; return 0; @@ -144,11 +154,8 @@ static void hashtable_do_clear(hashtable_t *hashtable) { next = list->next; pair = list_to_pair(list); - if(hashtable->free_key) - hashtable->free_key(pair->key); - if(hashtable->free_value) - hashtable->free_value(pair->value); - free(pair); + json_decref(pair->value); + jsonp_free(pair); } } @@ -156,14 +163,14 @@ static int hashtable_do_rehash(hashtable_t *hashtable) { list_t *list, *next; pair_t *pair; - unsigned int i, index, new_size; + size_t i, index, new_size; - free(hashtable->buckets); + jsonp_free(hashtable->buckets); hashtable->num_buckets++; new_size = num_buckets(hashtable); - hashtable->buckets = malloc(new_size * sizeof(bucket_t)); + hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); if(!hashtable->buckets) return -1; @@ -187,47 +194,18 @@ static int hashtable_do_rehash(hashtable_t *hashtable) } -hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value) +int hashtable_init(hashtable_t *hashtable) { - hashtable_t *hashtable = malloc(sizeof(hashtable_t)); - if(!hashtable) - return NULL; - - if(hashtable_init(hashtable, hash_key, cmp_keys, free_key, free_value)) - { - free(hashtable); - return NULL; - } - - return hashtable; -} - -void hashtable_destroy(hashtable_t *hashtable) -{ - hashtable_close(hashtable); - free(hashtable); -} - -int hashtable_init(hashtable_t *hashtable, - key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value) -{ - unsigned int i; + size_t i; hashtable->size = 0; hashtable->num_buckets = 0; /* index to primes[] */ - hashtable->buckets = malloc(num_buckets(hashtable) * sizeof(bucket_t)); + hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t)); if(!hashtable->buckets) return -1; list_init(&hashtable->list); - hashtable->hash_key = hash_key; - hashtable->cmp_keys = cmp_keys; - hashtable->free_key = free_key; - hashtable->free_value = free_value; - for(i = 0; i < num_buckets(hashtable); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = @@ -240,42 +218,45 @@ int hashtable_init(hashtable_t *hashtable, void hashtable_close(hashtable_t *hashtable) { hashtable_do_clear(hashtable); - free(hashtable->buckets); + jsonp_free(hashtable->buckets); } -int hashtable_set(hashtable_t *hashtable, void *key, void *value) +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value) { pair_t *pair; bucket_t *bucket; - unsigned int hash, index; + size_t hash, index; /* rehash if the load ratio exceeds 1 */ if(hashtable->size >= num_buckets(hashtable)) if(hashtable_do_rehash(hashtable)) return -1; - hash = hashtable->hash_key(key); + hash = hash_str(key); index = hash % num_buckets(hashtable); bucket = &hashtable->buckets[index]; pair = hashtable_find_pair(hashtable, bucket, key, hash); if(pair) { - if(hashtable->free_key) - hashtable->free_key(key); - if(hashtable->free_value) - hashtable->free_value(pair->value); + json_decref(pair->value); pair->value = value; } else { - pair = malloc(sizeof(pair_t)); + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1); if(!pair) return -1; - pair->key = key; - pair->value = value; pair->hash = hash; + pair->serial = serial; + strcpy(pair->key, key); + pair->value = value; list_init(&pair->list); insert_to_bucket(hashtable, bucket, &pair->list); @@ -285,13 +266,13 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value) return 0; } -void *hashtable_get(hashtable_t *hashtable, const void *key) +void *hashtable_get(hashtable_t *hashtable, const char *key) { pair_t *pair; - unsigned int hash; + size_t hash; bucket_t *bucket; - hash = hashtable->hash_key(key); + hash = hash_str(key); bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; pair = hashtable_find_pair(hashtable, bucket, key, hash); @@ -301,15 +282,15 @@ void *hashtable_get(hashtable_t *hashtable, const void *key) return pair->value; } -int hashtable_del(hashtable_t *hashtable, const void *key) +int hashtable_del(hashtable_t *hashtable, const char *key) { - unsigned int hash = hashtable->hash_key(key); + size_t hash = hash_str(key); return hashtable_do_del(hashtable, key, hash); } void hashtable_clear(hashtable_t *hashtable) { - unsigned int i; + size_t i; hashtable_do_clear(hashtable); @@ -328,13 +309,13 @@ void *hashtable_iter(hashtable_t *hashtable) return hashtable_iter_next(hashtable, &hashtable->list); } -void *hashtable_iter_at(hashtable_t *hashtable, const void *key) +void *hashtable_iter_at(hashtable_t *hashtable, const char *key) { pair_t *pair; - unsigned int hash; + size_t hash; bucket_t *bucket; - hash = hashtable->hash_key(key); + hash = hash_str(key); bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; pair = hashtable_find_pair(hashtable, bucket, key, hash); @@ -358,18 +339,22 @@ void *hashtable_iter_key(void *iter) return pair->key; } +size_t hashtable_iter_serial(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->serial; +} + void *hashtable_iter_value(void *iter) { pair_t *pair = list_to_pair((list_t *)iter); return pair->value; } -void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value) +void hashtable_iter_set(void *iter, json_t *value) { pair_t *pair = list_to_pair((list_t *)iter); - if(hashtable->free_value) - hashtable->free_value(pair->value); - + json_decref(pair->value); pair->value = value; } diff --git a/compat/jansson/hashtable.h b/compat/jansson/hashtable.h index f03a7690b..4a7ce6f67 100644 --- a/compat/jansson/hashtable.h +++ b/compat/jansson/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,20 +8,20 @@ #ifndef HASHTABLE_H #define HASHTABLE_H -typedef unsigned int (*key_hash_fn)(const void *key); -typedef int (*key_cmp_fn)(const void *key1, const void *key2); -typedef void (*free_fn)(void *key); - struct hashtable_list { struct hashtable_list *prev; struct hashtable_list *next; }; +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ struct hashtable_pair { - void *key; - void *value; - unsigned int hash; + size_t hash; struct hashtable_list list; + json_t *value; + size_t serial; + char key[1]; }; struct hashtable_bucket { @@ -30,60 +30,27 @@ struct hashtable_bucket { }; typedef struct hashtable { - unsigned int size; + size_t size; struct hashtable_bucket *buckets; - unsigned int num_buckets; /* index to primes[] */ + size_t num_buckets; /* index to primes[] */ struct hashtable_list list; - - key_hash_fn hash_key; - key_cmp_fn cmp_keys; /* returns non-zero for equal keys */ - free_fn free_key; - free_fn free_value; } hashtable_t; -/** - * hashtable_create - Create a hashtable object - * - * @hash_key: The key hashing function - * @cmp_keys: The key compare function. Returns non-zero for equal and - * zero for unequal unequal keys - * @free_key: If non-NULL, called for a key that is no longer referenced. - * @free_value: If non-NULL, called for a value that is no longer referenced. - * - * Returns a new hashtable object that should be freed with - * hashtable_destroy when it's no longer used, or NULL on failure (out - * of memory). - */ -hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value); -/** - * hashtable_destroy - Destroy a hashtable object - * - * @hashtable: The hashtable - * - * Destroys a hashtable created with hashtable_create(). - */ -void hashtable_destroy(hashtable_t *hashtable); +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->list)) /** * hashtable_init - Initialize a hashtable object * * @hashtable: The (statically allocated) hashtable object - * @hash_key: The key hashing function - * @cmp_keys: The key compare function. Returns non-zero for equal and - * zero for unequal unequal keys - * @free_key: If non-NULL, called for a key that is no longer referenced. - * @free_value: If non-NULL, called for a value that is no longer referenced. * * Initializes a statically allocated hashtable object. The object * should be cleared with hashtable_close when it's no longer used. * * Returns 0 on success, -1 on error (out of memory). */ -int hashtable_init(hashtable_t *hashtable, - key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value); +int hashtable_init(hashtable_t *hashtable); /** * hashtable_close - Release all resources used by a hashtable object @@ -99,20 +66,19 @@ void hashtable_close(hashtable_t *hashtable); * * @hashtable: The hashtable object * @key: The key + * @serial: For addition order of keys * @value: The value * * If a value with the given key already exists, its value is replaced - * with the new value. - * - * Key and value are "stealed" in the sense that hashtable frees them - * automatically when they are no longer used. The freeing is - * accomplished by calling free_key and free_value functions that were - * supplied to hashtable_new. In case one or both of the free - * functions is NULL, the corresponding item is not "stealed". + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. * * Returns 0 on success, -1 on failure (out of memory). */ -int hashtable_set(hashtable_t *hashtable, void *key, void *value); +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value); /** * hashtable_get - Get a value associated with a key @@ -122,7 +88,7 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value); * * Returns value if it is found, or NULL otherwise. */ -void *hashtable_get(hashtable_t *hashtable, const void *key); +void *hashtable_get(hashtable_t *hashtable, const char *key); /** * hashtable_del - Remove a value from the hashtable @@ -132,7 +98,7 @@ void *hashtable_get(hashtable_t *hashtable, const void *key); * * Returns 0 on success, or -1 if the key was not found. */ -int hashtable_del(hashtable_t *hashtable, const void *key); +int hashtable_del(hashtable_t *hashtable, const char *key); /** * hashtable_clear - Clear hashtable @@ -169,7 +135,7 @@ void *hashtable_iter(hashtable_t *hashtable); * Like hashtable_iter() but returns an iterator pointing to a * specific key. */ -void *hashtable_iter_at(hashtable_t *hashtable, const void *key); +void *hashtable_iter_at(hashtable_t *hashtable, const char *key); /** * hashtable_iter_next - Advance an iterator @@ -189,6 +155,13 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter); */ void *hashtable_iter_key(void *iter); +/** + * hashtable_iter_serial - Retrieve the serial number pointed to by an iterator + * + * @iter: The iterator + */ +size_t hashtable_iter_serial(void *iter); + /** * hashtable_iter_value - Retrieve the value pointed by an iterator * @@ -202,6 +175,6 @@ void *hashtable_iter_value(void *iter); * @iter: The iterator * @value: The value to set */ -void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value); +void hashtable_iter_set(void *iter, json_t *value); #endif diff --git a/compat/jansson/jansson.h b/compat/jansson/jansson.h index 4c526fee1..c192ffa96 100644 --- a/compat/jansson/jansson.h +++ b/compat/jansson/jansson.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -9,14 +9,31 @@ #define JANSSON_H #include +#include /* for size_t */ +#include -#ifndef __cplusplus -#define JSON_INLINE inline -#else -#define JSON_INLINE inline +#include + +#ifdef __cplusplus extern "C" { #endif +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 6 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.6" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \ + (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + + /* types */ typedef enum { @@ -30,11 +47,25 @@ typedef enum { JSON_NULL } json_type; -typedef struct { +typedef struct json_t { json_type type; - unsigned long refcount; + size_t refcount; } json_t; +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + #define json_typeof(json) ((json)->type) #define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) #define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY) @@ -53,16 +84,17 @@ json_t *json_object(void); json_t *json_array(void); json_t *json_string(const char *value); json_t *json_string_nocheck(const char *value); -json_t *json_integer(int value); +json_t *json_integer(json_int_t value); json_t *json_real(double value); json_t *json_true(void); json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) json_t *json_null(void); static JSON_INLINE json_t *json_incref(json_t *json) { - if(json && json->refcount != (unsigned int)-1) + if(json && json->refcount != (size_t)-1) ++json->refcount; return json; } @@ -73,27 +105,54 @@ void json_delete(json_t *json); static JSON_INLINE void json_decref(json_t *json) { - if(json && json->refcount != (unsigned int)-1 && --json->refcount == 0) + if(json && json->refcount != (size_t)-1 && --json->refcount == 0) json_delete(json); } +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + + /* getters, setters, manipulation */ -unsigned int json_object_size(const json_t *object); +size_t json_object_size(const json_t *object); json_t *json_object_get(const json_t *object, const char *key); int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); int json_object_del(json_t *object, const char *key); int json_object_clear(json_t *object); int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); void *json_object_iter(json_t *object); void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); void *json_object_iter_next(json_t *object, void *iter); const char *json_object_iter_key(void *iter); json_t *json_object_iter_value(void *iter); int json_object_iter_set_new(json_t *object, void *iter, json_t *value); +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) + +#define json_array_foreach(array, index, value) \ + for(index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *value) { @@ -106,25 +165,25 @@ int json_object_set_nocheck(json_t *object, const char *key, json_t *value) return json_object_set_new_nocheck(object, key, json_incref(value)); } -static inline +static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) { return json_object_iter_set_new(object, iter, json_incref(value)); } -unsigned int json_array_size(const json_t *array); -json_t *json_array_get(const json_t *array, unsigned int index); -int json_array_set_new(json_t *array, unsigned int index, json_t *value); +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index); +int json_array_set_new(json_t *array, size_t index, json_t *value); int json_array_append_new(json_t *array, json_t *value); -int json_array_insert_new(json_t *array, unsigned int index, json_t *value); -int json_array_remove(json_t *array, unsigned int index); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); int json_array_clear(json_t *array); int json_array_extend(json_t *array, json_t *other); static JSON_INLINE -int json_array_set(json_t *array, unsigned int index, json_t *value) +int json_array_set(json_t *array, size_t ind, json_t *value) { - return json_array_set_new(array, index, json_incref(value)); + return json_array_set_new(array, ind, json_incref(value)); } static JSON_INLINE @@ -134,22 +193,36 @@ int json_array_append(json_t *array, json_t *value) } static JSON_INLINE -int json_array_insert(json_t *array, unsigned int index, json_t *value) +int json_array_insert(json_t *array, size_t ind, json_t *value) { - return json_array_insert_new(array, index, json_incref(value)); + return json_array_insert_new(array, ind, json_incref(value)); } const char *json_string_value(const json_t *string); -int json_integer_value(const json_t *integer); +json_int_t json_integer_value(const json_t *integer); double json_real_value(const json_t *real); double json_number_value(const json_t *json); int json_string_set(json_t *string, const char *value); int json_string_set_nocheck(json_t *string, const char *value); -int json_integer_set(json_t *integer, int value); +int json_integer_set(json_t *integer, json_int_t value); int json_real_set(json_t *real, double value); +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); + + /* equality */ int json_equal(json_t *value1, json_t *value2); @@ -158,31 +231,48 @@ int json_equal(json_t *value1, json_t *value2); /* copying */ json_t *json_copy(json_t *value); -json_t *json_deep_copy(json_t *value); +json_t *json_deep_copy(const json_t *value); -/* loading, printing */ +/* decoding */ -#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 -typedef struct { - char text[JSON_ERROR_TEXT_LENGTH]; - int line; -} json_error_t; +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); + + +/* encoding */ + +#define JSON_INDENT(n) (n & 0x1F) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); -json_t *json_loads(const char *input, json_error_t *error); -json_t *json_loadf(FILE *input, json_error_t *error); -json_t *json_load_file(const char *path, json_error_t *error); +/* custom memory allocation */ -#define JSON_INDENT(n) (n & 0xFF) -#define JSON_COMPACT 0x100 -#define JSON_ENSURE_ASCII 0x200 -#define JSON_SORT_KEYS 0x400 -#define JSON_PRESERVE_ORDER 0x800 +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); -char *json_dumps(const json_t *json, unsigned long flags); -int json_dumpf(const json_t *json, FILE *output, unsigned long flags); -int json_dump_file(const json_t *json, const char *path, unsigned long flags); +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); #ifdef __cplusplus } diff --git a/compat/jansson/jansson_config.h b/compat/jansson/jansson_config.h new file mode 100644 index 000000000..90ca12928 --- /dev/null +++ b/compat/jansson/jansson_config.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ + +#ifdef _MSC_VER +#define inline __inline +#endif + +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 1 + +#endif diff --git a/compat/jansson/jansson_private.h b/compat/jansson/jansson_private.h index 4490702aa..403b53a4d 100644 --- a/compat/jansson/jansson_private.h +++ b/compat/jansson/jansson_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,23 +8,40 @@ #ifndef JANSSON_PRIVATE_H #define JANSSON_PRIVATE_H +#include #include "jansson.h" #include "hashtable.h" +#include "strbuffer.h" #define container_of(ptr_, type_, member_) \ - ((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_)) + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif typedef struct { json_t json; hashtable_t hashtable; - unsigned long serial; + size_t serial; int visited; } json_object_t; typedef struct { json_t json; - unsigned int size; - unsigned int entries; + size_t size; + size_t entries; json_t **table; int visited; } json_array_t; @@ -41,7 +58,7 @@ typedef struct { typedef struct { json_t json; - int value; + json_int_t value; } json_integer_t; #define json_to_object(json_) container_of(json_, json_object_t, json) @@ -50,11 +67,27 @@ typedef struct { #define json_to_real(json_) container_of(json_, json_real_t, json) #define json_to_integer(json_) container_of(json_, json_integer_t, json) -typedef struct { - unsigned long serial; - char key[]; -} object_key_t; +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value); -const object_key_t *jsonp_object_iter_fullkey(void *iter); +/* Wrappers for custom memory functions */ +void* jsonp_malloc(size_t size); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length); +char *jsonp_strdup(const char *str); + +/* Windows compatibility */ +#ifdef _WIN32 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif #endif diff --git a/compat/jansson/load.c b/compat/jansson/load.c index d49a4da5e..c5536f586 100644 --- a/compat/jansson/load.c +++ b/compat/jansson/load.c @@ -1,25 +1,30 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE -#include +#endif + #include #include #include #include #include -#include #include -#include +#include "jansson.h" #include "jansson_private.h" #include "strbuffer.h" #include "utf.h" +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + #define TOKEN_INVALID -1 #define TOKEN_EOF 0 #define TOKEN_STRING 256 @@ -29,113 +34,136 @@ #define TOKEN_FALSE 260 #define TOKEN_NULL 261 -/* read one byte from stream, return EOF on end of file */ +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ typedef int (*get_func)(void *data); -/* return non-zero if end of file has been reached */ -typedef int (*eof_func)(void *data); - typedef struct { get_func get; - eof_func eof; void *data; - int stream_pos; char buffer[5]; - int buffer_pos; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; } stream_t; - typedef struct { stream_t stream; strbuffer_t saved_text; int token; - int line, column; union { char *string; - int integer; + json_int_t integer; double real; } value; } lex_t; +#define stream_to_lex(stream) container_of(stream, lex_t, stream) -/*** error reporting ***/ -static void error_init(json_error_t *error) -{ - if(error) - { - error->text[0] = '\0'; - error->line = -1; - } -} +/*** error reporting ***/ static void error_set(json_error_t *error, const lex_t *lex, const char *msg, ...) { va_list ap; - char text[JSON_ERROR_TEXT_LENGTH]; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; - if(!error || error->text[0] != '\0') { - /* error already set */ + if(!error) return; - } va_start(ap, msg); - vsnprintf(text, JSON_ERROR_TEXT_LENGTH, msg, ap); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; va_end(ap); if(lex) { const char *saved_text = strbuffer_value(&lex->saved_text); - error->line = lex->line; + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + if(saved_text && saved_text[0]) { if(lex->saved_text.length <= 20) { - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, - "%s near '%s'", text, saved_text); + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near '%s'", msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; } - else - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text); } else { - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, - "%s near end of file", text); + if(lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } + else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near end of file", msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } } } - else - { - error->line = -1; - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text); - } + + jsonp_error_set(error, line, col, pos, "%s", result); } /*** lexical analyzer ***/ static void -stream_init(stream_t *stream, get_func get, eof_func eof, void *data) +stream_init(stream_t *stream, get_func get, void *data) { stream->get = get; - stream->eof = eof; stream->data = data; - stream->stream_pos = 0; stream->buffer[0] = '\0'; stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; } -static char stream_get(stream_t *stream, json_error_t *error) +static int stream_get(stream_t *stream, json_error_t *error) { - char c; + int c; + + if(stream->state != STREAM_STATE_OK) + return stream->state; if(!stream->buffer[stream->buffer_pos]) { - stream->buffer[0] = stream->get(stream->data); - stream->buffer_pos = 0; + c = stream->get(stream->data); + if(c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } - c = stream->buffer[0]; + stream->buffer[0] = c; + stream->buffer_pos = 0; - if((unsigned char)c >= 0x80 && c != (char)EOF) + if(0x80 <= c && c <= 0xFF) { /* multi-byte UTF-8 sequence */ int i, count; @@ -152,30 +180,47 @@ static char stream_get(stream_t *stream, json_error_t *error) if(!utf8_check_full(stream->buffer, count, NULL)) goto out; - stream->stream_pos += count; stream->buffer[count] = '\0'; } - else { + else stream->buffer[1] = '\0'; - stream->stream_pos++; - } } - return stream->buffer[stream->buffer_pos++]; + c = stream->buffer[stream->buffer_pos++]; -out: - error_set(error, NULL, "unable to decode byte 0x%x at position %d", - (unsigned char)c, stream->stream_pos); + stream->position++; + if(c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } + else if(utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } - stream->buffer[0] = EOF; - stream->buffer[1] = '\0'; - stream->buffer_pos = 1; + return c; - return EOF; +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; } -static void stream_unget(stream_t *stream, char c) +static void stream_unget(stream_t *stream, int c) { + if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if(c == '\n') { + stream->line--; + stream->column = stream->last_column; + } + else if(utf8_check_first(c)) + stream->column--; + assert(stream->buffer_pos > 0); stream->buffer_pos--; assert(stream->buffer[stream->buffer_pos] == c); @@ -187,29 +232,41 @@ static int lex_get(lex_t *lex, json_error_t *error) return stream_get(&lex->stream, error); } -static int lex_eof(lex_t *lex) -{ - return lex->stream.eof(lex->stream.data); -} - -static void lex_save(lex_t *lex, char c) +static void lex_save(lex_t *lex, int c) { strbuffer_append_byte(&lex->saved_text, c); } static int lex_get_save(lex_t *lex, json_error_t *error) { - char c = stream_get(&lex->stream, error); - lex_save(lex, c); + int c = stream_get(&lex->stream, error); + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); return c; } -static void lex_unget_unsave(lex_t *lex, char c) +static void lex_unget(lex_t *lex, int c) { - char d; stream_unget(&lex->stream, c); - d = strbuffer_pop(&lex->saved_text); - assert(c == d); +} + +static void lex_unget_unsave(lex_t *lex, int c) +{ + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { + /* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ + #ifndef NDEBUG + char d; + #endif + stream_unget(&lex->stream, c); + #ifndef NDEBUG + d = + #endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } } static void lex_save_cached(lex_t *lex) @@ -218,6 +275,7 @@ static void lex_save_cached(lex_t *lex) { lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); lex->stream.buffer_pos++; + lex->stream.position++; } } @@ -232,11 +290,11 @@ static int32_t decode_unicode_escape(const char *str) for(i = 1; i <= 4; i++) { char c = str[i]; value <<= 4; - if(isdigit(c)) + if(l_isdigit(c)) value += c - '0'; - else if(islower(c)) + else if(l_islower(c)) value += c - 'a' + 10; - else if(isupper(c)) + else if(l_isupper(c)) value += c - 'A' + 10; else assert(0); @@ -247,7 +305,7 @@ static int32_t decode_unicode_escape(const char *str) static void lex_scan_string(lex_t *lex, json_error_t *error) { - char c; + int c; const char *p; char *t; int i; @@ -258,14 +316,15 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) c = lex_get_save(lex, error); while(c != '"') { - if(c == (char)EOF) { - lex_unget_unsave(lex, c); - if(lex_eof(lex)) - error_set(error, lex, "premature end of input"); + if(c == STREAM_STATE_ERROR) + goto out; + + else if(c == STREAM_STATE_EOF) { + error_set(error, lex, "premature end of input"); goto out; } - else if((unsigned char)c <= 0x1F) { + else if(0 <= c && c <= 0x1F) { /* control character */ lex_unget_unsave(lex, c); if(c == '\n') @@ -280,8 +339,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) if(c == 'u') { c = lex_get_save(lex, error); for(i = 0; i < 4; i++) { - if(!isxdigit(c)) { - lex_unget_unsave(lex, c); + if(!l_isxdigit(c)) { error_set(error, lex, "invalid escape"); goto out; } @@ -292,7 +350,6 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) c == 'f' || c == 'n' || c == 'r' || c == 't') c = lex_get_save(lex, error); else { - lex_unget_unsave(lex, c); error_set(error, lex, "invalid escape"); goto out; } @@ -308,7 +365,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair are converted to 4 bytes */ - lex->value.string = malloc(lex->saved_text.length + 1); + lex->value.string = jsonp_malloc(lex->saved_text.length + 1); if(!lex->value.string) { /* this is not very nice, since TOKEN_INVALID is returned */ goto out; @@ -398,10 +455,22 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) return; out: - free(lex->value.string); + jsonp_free(lex->value.string); } -static int lex_scan_number(lex_t *lex, char c, json_error_t *error) +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) { const char *saved_text; char *end; @@ -414,52 +483,55 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error) if(c == '0') { c = lex_get_save(lex, error); - if(isdigit(c)) { + if(l_isdigit(c)) { lex_unget_unsave(lex, c); goto out; } } - else if(isdigit(c)) { + else if(l_isdigit(c)) { c = lex_get_save(lex, error); - while(isdigit(c)) + while(l_isdigit(c)) c = lex_get_save(lex, error); } else { - lex_unget_unsave(lex, c); - goto out; + lex_unget_unsave(lex, c); + goto out; } if(c != '.' && c != 'E' && c != 'e') { - long value; + json_int_t value; lex_unget_unsave(lex, c); saved_text = strbuffer_value(&lex->saved_text); - value = strtol(saved_text, &end, 10); - assert(end == saved_text + lex->saved_text.length); - if((value == LONG_MAX && errno == ERANGE) || value > INT_MAX) { - error_set(error, lex, "too big integer"); - goto out; - } - else if((value == LONG_MIN && errno == ERANGE) || value < INT_MIN) { - error_set(error, lex, "too big negative integer"); + errno = 0; + value = json_strtoint(saved_text, &end, 10); + if(errno == ERANGE) { + if(value < 0) + error_set(error, lex, "too big negative integer"); + else + error_set(error, lex, "too big integer"); goto out; } + assert(end == saved_text + lex->saved_text.length); + lex->token = TOKEN_INTEGER; - lex->value.integer = (int)value; + lex->value.integer = value; return 0; } if(c == '.') { c = lex_get(lex, error); - if(!isdigit(c)) + if(!l_isdigit(c)) { + lex_unget(lex, c); goto out; + } lex_save(lex, c); c = lex_get_save(lex, error); - while(isdigit(c)) + while(l_isdigit(c)) c = lex_get_save(lex, error); } @@ -468,23 +540,19 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error) if(c == '+' || c == '-') c = lex_get_save(lex, error); - if(!isdigit(c)) { + if(!l_isdigit(c)) { lex_unget_unsave(lex, c); goto out; } c = lex_get_save(lex, error); - while(isdigit(c)) + while(l_isdigit(c)) c = lex_get_save(lex, error); } lex_unget_unsave(lex, c); - saved_text = strbuffer_value(&lex->saved_text); - value = strtod(saved_text, &end); - assert(end == saved_text + lex->saved_text.length); - - if(errno == ERANGE && value != 0) { + if(jsonp_strtod(&lex->saved_text, &value)) { error_set(error, lex, "real number overflow"); goto out; } @@ -499,29 +567,26 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error) static int lex_scan(lex_t *lex, json_error_t *error) { - char c; + int c; strbuffer_clear(&lex->saved_text); if(lex->token == TOKEN_STRING) { - free(lex->value.string); + jsonp_free(lex->value.string); lex->value.string = NULL; } c = lex_get(lex, error); while(c == ' ' || c == '\t' || c == '\n' || c == '\r') - { - if(c == '\n') - lex->line++; - c = lex_get(lex, error); + + if(c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; } - if(c == (char)EOF) { - if(lex_eof(lex)) - lex->token = TOKEN_EOF; - else - lex->token = TOKEN_INVALID; + if(c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; goto out; } @@ -533,17 +598,17 @@ static int lex_scan(lex_t *lex, json_error_t *error) else if(c == '"') lex_scan_string(lex, error); - else if(isdigit(c) || c == '-') { + else if(l_isdigit(c) || c == '-') { if(lex_scan_number(lex, c, error)) goto out; } - else if(isupper(c) || islower(c)) { + else if(l_isalpha(c)) { /* eat up the whole identifier for clearer error messages */ const char *saved_text; c = lex_get_save(lex, error); - while(isupper(c) || islower(c)) + while(l_isalpha(c)) c = lex_get_save(lex, error); lex_unget_unsave(lex, c); @@ -581,31 +646,29 @@ static char *lex_steal_string(lex_t *lex) return result; } -static int lex_init(lex_t *lex, get_func get, eof_func eof, void *data) +static int lex_init(lex_t *lex, get_func get, void *data) { - stream_init(&lex->stream, get, eof, data); + stream_init(&lex->stream, get, data); if(strbuffer_init(&lex->saved_text)) return -1; lex->token = TOKEN_INVALID; - lex->line = 1; - return 0; } static void lex_close(lex_t *lex) { if(lex->token == TOKEN_STRING) - free(lex->value.string); + jsonp_free(lex->value.string); strbuffer_close(&lex->saved_text); } /*** parser ***/ -static json_t *parse_value(lex_t *lex, json_error_t *error); +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); -static json_t *parse_object(lex_t *lex, json_error_t *error) +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { json_t *object = json_object(); if(!object) @@ -628,28 +691,36 @@ static json_t *parse_object(lex_t *lex, json_error_t *error) if(!key) return NULL; + if(flags & JSON_REJECT_DUPLICATES) { + if(json_object_get(object, key)) { + jsonp_free(key); + error_set(error, lex, "duplicate object key"); + goto error; + } + } + lex_scan(lex, error); if(lex->token != ':') { - free(key); + jsonp_free(key); error_set(error, lex, "':' expected"); goto error; } lex_scan(lex, error); - value = parse_value(lex, error); + value = parse_value(lex, flags, error); if(!value) { - free(key); + jsonp_free(key); goto error; } if(json_object_set_nocheck(object, key, value)) { - free(key); + jsonp_free(key); json_decref(value); goto error; } json_decref(value); - free(key); + jsonp_free(key); lex_scan(lex, error); if(lex->token != ',') @@ -670,7 +741,7 @@ static json_t *parse_object(lex_t *lex, json_error_t *error) return NULL; } -static json_t *parse_array(lex_t *lex, json_error_t *error) +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) { json_t *array = json_array(); if(!array) @@ -681,7 +752,7 @@ static json_t *parse_array(lex_t *lex, json_error_t *error) return array; while(lex->token) { - json_t *elem = parse_value(lex, error); + json_t *elem = parse_value(lex, flags, error); if(!elem) goto error; @@ -710,9 +781,10 @@ static json_t *parse_array(lex_t *lex, json_error_t *error) return NULL; } -static json_t *parse_value(lex_t *lex, json_error_t *error) +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) { json_t *json; + double value; switch(lex->token) { case TOKEN_STRING: { @@ -721,7 +793,15 @@ static json_t *parse_value(lex_t *lex, json_error_t *error) } case TOKEN_INTEGER: { - json = json_integer(lex->value.integer); + if (flags & JSON_DECODE_INT_AS_REAL) { + if(jsonp_strtod(&lex->saved_text, &value)) { + error_set(error, lex, "real number overflow"); + return NULL; + } + json = json_real(value); + } else { + json = json_integer(lex->value.integer); + } break; } @@ -743,11 +823,11 @@ static json_t *parse_value(lex_t *lex, json_error_t *error) break; case '{': - json = parse_object(lex, error); + json = parse_object(lex, flags, error); break; case '[': - json = parse_array(lex, error); + json = parse_array(lex, flags, error); break; case TOKEN_INVALID: @@ -765,17 +845,37 @@ static json_t *parse_value(lex_t *lex, json_error_t *error) return json; } -static json_t *parse_json(lex_t *lex, json_error_t *error) +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) { - error_init(error); + json_t *result; lex_scan(lex, error); - if(lex->token != '[' && lex->token != '{') { - error_set(error, lex, "'[' or '{' expected"); + if(!(flags & JSON_DECODE_ANY)) { + if(lex->token != '[' && lex->token != '{') { + error_set(error, lex, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if(!result) return NULL; + + if(!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if(lex->token != TOKEN_EOF) { + error_set(error, lex, "end of file expected"); + json_decref(result); + return NULL; + } + } + + if(error) { + /* Save the position even though there was no error */ + error->position = lex->stream.position; } - return parse_value(lex, error); + return result; } typedef struct @@ -794,77 +894,120 @@ static int string_get(void *data) else { stream->pos++; - return c; + return (unsigned char)c; } } -static int string_eof(void *data) +json_t *json_loads(const char *string, size_t flags, json_error_t *error) { - string_data_t *stream = (string_data_t *)data; - return (stream->data[stream->pos] == '\0'); + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, ""); + + if (string == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if(lex_init(&lex, string_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct +{ + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) +{ + char c; + buffer_data_t *stream = data; + if(stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; } -json_t *json_loads(const char *string, json_error_t *error) +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) { lex_t lex; json_t *result; + buffer_data_t stream_data; - string_data_t stream_data = { - .data = string, - .pos = 0 - }; + jsonp_error_init(error, ""); - if(lex_init(&lex, string_get, string_eof, (void *)&stream_data)) + if (buffer == NULL) { + error_set(error, NULL, "wrong arguments"); return NULL; + } - result = parse_json(&lex, error); - if(!result) - goto out; + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; - lex_scan(&lex, error); - if(lex.token != TOKEN_EOF) { - error_set(error, &lex, "end of file expected"); - json_decref(result); - result = NULL; - } + if(lex_init(&lex, buffer_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); -out: lex_close(&lex); return result; } -json_t *json_loadf(FILE *input, json_error_t *error) +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) { lex_t lex; + const char *source; json_t *result; - if(lex_init(&lex, (get_func)fgetc, (eof_func)feof, input)) - return NULL; + if(input == stdin) + source = ""; + else + source = ""; - result = parse_json(&lex, error); - if(!result) - goto out; + jsonp_error_init(error, source); - lex_scan(&lex, error); - if(lex.token != TOKEN_EOF) { - error_set(error, &lex, "end of file expected"); - json_decref(result); - result = NULL; + if (input == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; } -out: + if(lex_init(&lex, (get_func)fgetc, input)) + return NULL; + + result = parse_json(&lex, flags, error); + lex_close(&lex); return result; } -json_t *json_load_file(const char *path, json_error_t *error) +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) { json_t *result; FILE *fp; - error_init(error); + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } - fp = fopen(path, "r"); + fp = fopen(path, "rb"); if(!fp) { error_set(error, NULL, "unable to open %s: %s", @@ -872,8 +1015,63 @@ json_t *json_load_file(const char *path, json_error_t *error) return NULL; } - result = json_loadf(fp, error); + result = json_loadf(fp, flags, error); fclose(fp); return result; } + +#define MAX_BUF_LEN 1024 + +typedef struct +{ + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) +{ + char c; + callback_data_t *stream = data; + + if(stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if(stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, ""); + + if (callback == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)callback_get, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/compat/jansson/memory.c b/compat/jansson/memory.c new file mode 100644 index 000000000..eb6cec542 --- /dev/null +++ b/compat/jansson/memory.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2011-2012 Basile Starynkevitch + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include "jansson.h" +#include "jansson_private.h" + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) +{ + if(!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) +{ + if(!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) +{ + char *new_str; + size_t len; + + len = strlen(str); + if(len == (size_t)-1) + return NULL; + + new_str = jsonp_malloc(len + 1); + if(!new_str) + return NULL; + + memcpy(new_str, str, len + 1); + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) +{ + do_malloc = malloc_fn; + do_free = free_fn; +} diff --git a/compat/jansson/pack_unpack.c b/compat/jansson/pack_unpack.c new file mode 100644 index 000000000..0d932f791 --- /dev/null +++ b/compat/jansson/pack_unpack.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2011-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char * const type_names[] = { + "object", + "array", + "string", + "integer", + "real", + "true", + "false", + "null" +}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + + +static void scanner_init(scanner_t *s, json_error_t *error, + size_t flags, const char *fmt) +{ + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; +} + +static void next_token(scanner_t *s) +{ + const char *t; + s->prev_token = s->token; + + if(s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if(*t == '\n') { + s->line++; + s->column = 1; + } + else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) +{ + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, + fmt, ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, + const char *purpose, int *ours) +{ + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + char *result; + + next_token(s); + t = token(s); + prev_token(s); + + if(t != '#' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if(!str) { + set_error(s, "", "NULL string argument"); + return NULL; + } + + if(!utf8_check_string(str, -1)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *ours = 0; + return (char *)str; + } + + strbuffer_init(&strbuff); + + while(1) { + str = va_arg(*ap, const char *); + if(!str) { + set_error(s, "", "NULL string argument"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + + if(token(s) == '#') { + length = va_arg(*ap, int); + } + else { + prev_token(s); + length = strlen(str); + } + + if(strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "", "Out of memory"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + if(token(s) != '+') { + prev_token(s); + break; + } + } + + result = strbuffer_steal_value(&strbuff); + + if(!utf8_check_string(result, -1)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *ours = 1; + return result; +} + +static json_t *pack_object(scanner_t *s, va_list *ap) +{ + json_t *object = json_object(); + next_token(s); + + while(token(s) != '}') { + char *key; + int ours; + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &ours); + if(!key) + goto error; + + next_token(s); + + value = pack(s, ap); + if(!value) + goto error; + + if(json_object_set_new_nocheck(object, key, value)) { + if(ours) + jsonp_free(key); + + set_error(s, "", "Unable to add key \"%s\"", key); + goto error; + } + + if(ours) + jsonp_free(key); + + next_token(s); + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) +{ + json_t *array = json_array(); + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + value = pack(s, ap); + if(!value) + goto error; + + if(json_array_append_new(array, value)) { + set_error(s, "", "Unable to append to array"); + goto error; + } + + next_token(s); + } + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack(scanner_t *s, va_list *ap) +{ + switch(token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': { /* string */ + char *str; + int ours; + json_t *result; + + str = read_string(s, ap, "string", &ours); + if(!str) + return NULL; + + result = json_string_nocheck(str); + if(ours) + jsonp_free(str); + + return result; + } + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return json_integer(va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return json_integer(va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return json_real(va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return json_incref(va_arg(*ap, json_t *)); + + case 'o': /* a json_t object; doesn't increment refcount */ + return va_arg(*ap, json_t *); + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) +{ + int ret = -1; + int strict = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if(hashtable_init(&key_set)) { + set_error(s, "", "Out of memory"); + return -1; + } + + if(root && !json_is_object(root)) { + set_error(s, "", "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while(token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if(strict != 0) { + set_error(s, "", "Expected '}' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), token(s)); + goto out; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto out; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if(!key) { + set_error(s, "", "NULL object key"); + goto out; + } + + next_token(s); + + if(token(s) == '?') { + opt = 1; + next_token(s); + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_object_get(root, key); + if(!value && !opt) { + set_error(s, "", "Object item not found: %s", key); + goto out; + } + } + + if(unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, 0, json_null()); + next_token(s); + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && key_set.size != json_object_size(root)) { + long diff = (long)json_object_size(root) - (long)key_set.size; + set_error(s, "", "%li object item(s) left unpacked", diff); + goto out; + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) +{ + size_t i = 0; + int strict = 0; + + if(root && !json_is_array(root)) { + set_error(s, "", "Expected array, got %s", type_name(root)); + return -1; + } + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(strict != 0) { + set_error(s, "", "Expected ']' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + return -1; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(!strchr(unpack_value_starters, token(s))) { + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_array_get(root, i); + if(!value) { + set_error(s, "", "Array index %lu out of range", + (unsigned long)i); + return -1; + } + } + + if(unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "", "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) +{ + switch(token(s)) + { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if(root && !json_is_string(root)) { + set_error(s, "", "Expected string, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + const char **target; + + target = va_arg(*ap, const char **); + if(!target) { + set_error(s, "", "NULL string argument"); + return -1; + } + + if(root) + *target = json_string_value(root); + } + return 0; + + case 'i': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t*); + if(root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if(root && !json_is_boolean(root)) { + set_error(s, "", "Expected true or false, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if(root && !json_is_real(root)) { + set_error(s, "", "Expected real, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if(root && !json_is_number(root)) { + set_error(s, "", "Expected real or integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if(root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t**); + if(root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if(root && !json_is_null(root)) { + set_error(s, "", "Expected null, got %s", + type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + json_t *value; + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + if(!value) + return NULL; + + next_token(&s); + if(token(&s)) { + json_decref(value); + set_error(&s, "", "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + + if(!root) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL root value"); + return -1; + } + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if(unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if(token(&s)) { + set_error(&s, "", "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/compat/jansson/strbuffer.c b/compat/jansson/strbuffer.c index 349602477..2d6ff3105 100644 --- a/compat/jansson/strbuffer.c +++ b/compat/jansson/strbuffer.c @@ -1,25 +1,29 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif + #include #include +#include "jansson_private.h" #include "strbuffer.h" -#include "util.h" #define STRBUFFER_MIN_SIZE 16 #define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) int strbuffer_init(strbuffer_t *strbuff) { strbuff->size = STRBUFFER_MIN_SIZE; strbuff->length = 0; - strbuff->value = malloc(strbuff->size); + strbuff->value = jsonp_malloc(strbuff->size); if(!strbuff->value) return -1; @@ -30,7 +34,9 @@ int strbuffer_init(strbuffer_t *strbuff) void strbuffer_close(strbuffer_t *strbuff) { - free(strbuff->value); + if(strbuff->value) + jsonp_free(strbuff->value); + strbuff->size = 0; strbuff->length = 0; strbuff->value = NULL; @@ -50,7 +56,7 @@ const char *strbuffer_value(const strbuffer_t *strbuff) char *strbuffer_steal_value(strbuffer_t *strbuff) { char *result = strbuff->value; - strbuffer_init(strbuff); + strbuff->value = NULL; return result; } @@ -64,16 +70,31 @@ int strbuffer_append_byte(strbuffer_t *strbuff, char byte) return strbuffer_append_bytes(strbuff, &byte, 1); } -int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size) +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) { - if(strbuff->length + size >= strbuff->size) + if(size >= strbuff->size - strbuff->length) { - strbuff->size = max(strbuff->size * STRBUFFER_FACTOR, - strbuff->length + size + 1); + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR + || size > STRBUFFER_SIZE_MAX - 1 + || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, + strbuff->length + size + 1); - strbuff->value = realloc(strbuff->value, strbuff->size); - if(!strbuff->value) + new_value = jsonp_malloc(new_size); + if(!new_value) return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; } memcpy(strbuff->value + strbuff->length, data, size); diff --git a/compat/jansson/strbuffer.h b/compat/jansson/strbuffer.h index f4c5f7718..06fd065bb 100644 --- a/compat/jansson/strbuffer.h +++ b/compat/jansson/strbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -10,8 +10,8 @@ typedef struct { char *value; - int length; /* bytes used */ - int size; /* bytes allocated */ + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ } strbuffer_t; int strbuffer_init(strbuffer_t *strbuff); @@ -20,11 +20,13 @@ void strbuffer_close(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff); const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ char *strbuffer_steal_value(strbuffer_t *strbuff); int strbuffer_append(strbuffer_t *strbuff, const char *string); int strbuffer_append_byte(strbuffer_t *strbuff, char byte); -int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); char strbuffer_pop(strbuffer_t *strbuff); diff --git a/compat/jansson/strconv.c b/compat/jansson/strconv.c new file mode 100644 index 000000000..3e2cb7c4c --- /dev/null +++ b/compat/jansson/strconv.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +/* need config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if JSON_HAVE_LOCALECONV +#include + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if(pos) + *pos = *point; +} + +static void from_locale(char *buffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if(pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) +{ + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if(errno == ERANGE && value != 0) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value) +{ + int ret; + char *start, *end; + size_t length; + + ret = snprintf(buffer, size, "%.17g", value); + if(ret < 0) + return -1; + + length = (size_t)ret; + if(length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if(strchr(buffer, '.') == NULL && + strchr(buffer, 'e') == NULL) + { + if(length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if(start) { + start++; + end = start + 1; + + if(*start == '-') + start++; + + while(*end == '0') + end++; + + if(end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/compat/jansson/utf.c b/compat/jansson/utf.c index 92484d025..65b849b89 100644 --- a/compat/jansson/utf.c +++ b/compat/jansson/utf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. diff --git a/compat/jansson/utf.h b/compat/jansson/utf.h index d0ae6e931..cb10c24c1 100644 --- a/compat/jansson/utf.h +++ b/compat/jansson/utf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,6 +8,7 @@ #ifndef UTF_H #define UTF_H +#ifdef HAVE_CONFIG_H #include #ifdef HAVE_INTTYPES_H @@ -15,7 +16,17 @@ no need to include stdint.h separately. If inttypes.h doesn't define int32_t, it's defined in config.h. */ #include -#endif +#endif /* HAVE_INTTYPES_H */ + +#else /* !HAVE_CONFIG_H */ +#ifdef _WIN32 +typedef int int32_t; +#else /* !_WIN32 */ +/* Assume a standard environment */ +#include +#endif /* _WIN32 */ + +#endif /* HAVE_CONFIG_H */ int utf8_encode(int codepoint, char *buffer, int *size); diff --git a/compat/jansson/util.h b/compat/jansson/util.h index 06a547b8a..c4f033ac5 100644 --- a/compat/jansson/util.h +++ b/compat/jansson/util.h @@ -8,6 +8,8 @@ #ifndef UTIL_H #define UTIL_H +#ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) +#endif #endif diff --git a/compat/jansson/value.c b/compat/jansson/value.c index e024fdb1f..582849be3 100644 --- a/compat/jansson/value.c +++ b/compat/jansson/value.c @@ -1,25 +1,33 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif -#include - +#include #include #include +#include -#include +#include "jansson.h" #include "hashtable.h" #include "jansson_private.h" #include "utf.h" -#include "util.h" +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif -static inline void json_init(json_t *json, json_type type) +static JSON_INLINE void json_init(json_t *json, json_type type) { json->type = type; json->refcount = 1; @@ -28,50 +36,16 @@ static inline void json_init(json_t *json, json_type type) /*** object ***/ -/* This macro just returns a pointer that's a few bytes backwards from - string. This makes it possible to pass a pointer to object_key_t - when only the string inside it is used, without actually creating - an object_key_t instance. */ -#define string_to_key(string) container_of(string, object_key_t, key) - -static unsigned int hash_key(const void *ptr) -{ - const char *str = ((const object_key_t *)ptr)->key; - - unsigned int hash = 5381; - unsigned int c; - - while((c = (unsigned int)*str)) - { - hash = ((hash << 5) + hash) + c; - str++; - } - - return hash; -} - -static int key_equal(const void *ptr1, const void *ptr2) -{ - return strcmp(((const object_key_t *)ptr1)->key, - ((const object_key_t *)ptr2)->key) == 0; -} - -static void value_decref(void *value) -{ - json_decref((json_t *)value); -} - json_t *json_object(void) { - json_object_t *object = malloc(sizeof(json_object_t)); + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); if(!object) return NULL; json_init(&object->json, JSON_OBJECT); - if(hashtable_init(&object->hashtable, hash_key, key_equal, - free, value_decref)) + if(hashtable_init(&object->hashtable)) { - free(object); + jsonp_free(object); return NULL; } @@ -84,15 +58,15 @@ json_t *json_object(void) static void json_delete_object(json_object_t *object) { hashtable_close(&object->hashtable); - free(object); + jsonp_free(object); } -unsigned int json_object_size(const json_t *json) +size_t json_object_size(const json_t *json) { json_object_t *object; if(!json_is_object(json)) - return -1; + return 0; object = json_to_object(json); return object->hashtable.size; @@ -106,32 +80,24 @@ json_t *json_object_get(const json_t *json, const char *key) return NULL; object = json_to_object(json); - return hashtable_get(&object->hashtable, string_to_key(key)); + return hashtable_get(&object->hashtable, key); } int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) { json_object_t *object; - object_key_t *k; - if(!key || !value) + if(!value) return -1; - if(!json_is_object(json) || json == value) + if(!key || !json_is_object(json) || json == value) { json_decref(value); return -1; } object = json_to_object(json); - k = malloc(sizeof(object_key_t) + strlen(key) + 1); - if(!k) - return -1; - - k->serial = object->serial++; - strcpy(k->key, key); - - if(hashtable_set(&object->hashtable, k, value)) + if(hashtable_set(&object->hashtable, key, object->serial++, value)) { json_decref(value); return -1; @@ -159,7 +125,7 @@ int json_object_del(json_t *json, const char *key) return -1; object = json_to_object(json); - return hashtable_del(&object->hashtable, string_to_key(key)); + return hashtable_del(&object->hashtable, key); } int json_object_clear(json_t *json) @@ -170,30 +136,56 @@ int json_object_clear(json_t *json) return -1; object = json_to_object(json); + hashtable_clear(&object->hashtable); + object->serial = 0; return 0; } int json_object_update(json_t *object, json_t *other) { - void *iter; + const char *key; + json_t *value; if(!json_is_object(object) || !json_is_object(other)) return -1; - iter = json_object_iter(other); - while(iter) { - const char *key; - json_t *value; - - key = json_object_iter_key(iter); - value = json_object_iter_value(iter); - + json_object_foreach(other, key, value) { if(json_object_set_nocheck(object, key, value)) return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; - iter = json_object_iter_next(other, iter); + json_object_foreach(other, key, value) { + if(!json_object_get(object, key)) + json_object_set_nocheck(object, key, value); } return 0; @@ -218,7 +210,7 @@ void *json_object_iter_at(json_t *json, const char *key) return NULL; object = json_to_object(json); - return hashtable_iter_at(&object->hashtable, string_to_key(key)); + return hashtable_iter_at(&object->hashtable, key); } void *json_object_iter_next(json_t *json, void *iter) @@ -232,20 +224,12 @@ void *json_object_iter_next(json_t *json, void *iter) return hashtable_iter_next(&object->hashtable, iter); } -const object_key_t *jsonp_object_iter_fullkey(void *iter) -{ - if(!iter) - return NULL; - - return hashtable_iter_key(iter); -} - const char *json_object_iter_key(void *iter) { if(!iter) return NULL; - return jsonp_object_iter_fullkey(iter)->key; + return hashtable_iter_key(iter); } json_t *json_object_iter_value(void *iter) @@ -258,38 +242,34 @@ json_t *json_object_iter_value(void *iter) int json_object_iter_set_new(json_t *json, void *iter, json_t *value) { - json_object_t *object; - if(!json_is_object(json) || !iter || !value) return -1; - object = json_to_object(json); - hashtable_iter_set(&object->hashtable, iter, value); - + hashtable_iter_set(iter, value); return 0; } +void *json_object_key_to_iter(const char *key) +{ + if(!key) + return NULL; + + return hashtable_key_to_iter(key); +} + static int json_object_equal(json_t *object1, json_t *object2) { - void *iter; + const char *key; + json_t *value1, *value2; if(json_object_size(object1) != json_object_size(object2)) return 0; - iter = json_object_iter(object1); - while(iter) - { - const char *key; - json_t *value1, *value2; - - key = json_object_iter_key(iter); - value1 = json_object_iter_value(iter); + json_object_foreach(object1, key, value1) { value2 = json_object_get(object2, key); if(!json_equal(value1, value2)) return 0; - - iter = json_object_iter_next(object1, iter); } return 1; @@ -298,29 +278,21 @@ static int json_object_equal(json_t *object1, json_t *object2) static json_t *json_object_copy(json_t *object) { json_t *result; - void *iter; + + const char *key; + json_t *value; result = json_object(); if(!result) return NULL; - iter = json_object_iter(object); - while(iter) - { - const char *key; - json_t *value; - - key = json_object_iter_key(iter); - value = json_object_iter_value(iter); + json_object_foreach(object, key, value) json_object_set_nocheck(result, key, value); - iter = json_object_iter_next(object, iter); - } - return result; } -static json_t *json_object_deep_copy(json_t *object) +static json_t *json_object_deep_copy(const json_t *object) { json_t *result; void *iter; @@ -329,17 +301,17 @@ static json_t *json_object_deep_copy(json_t *object) if(!result) return NULL; - iter = json_object_iter(object); - while(iter) - { + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while(iter) { const char *key; - json_t *value; - + const json_t *value; key = json_object_iter_key(iter); value = json_object_iter_value(iter); - json_object_set_new_nocheck(result, key, json_deep_copy(value)); - iter = json_object_iter_next(object, iter); + json_object_set_new_nocheck(result, key, json_deep_copy(value)); + iter = json_object_iter_next((json_t *)object, iter); } return result; @@ -350,7 +322,7 @@ static json_t *json_object_deep_copy(json_t *object) json_t *json_array(void) { - json_array_t *array = malloc(sizeof(json_array_t)); + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); if(!array) return NULL; json_init(&array->json, JSON_ARRAY); @@ -358,9 +330,9 @@ json_t *json_array(void) array->entries = 0; array->size = 8; - array->table = malloc(array->size * sizeof(json_t *)); + array->table = jsonp_malloc(array->size * sizeof(json_t *)); if(!array->table) { - free(array); + jsonp_free(array); return NULL; } @@ -371,16 +343,16 @@ json_t *json_array(void) static void json_delete_array(json_array_t *array) { - unsigned int i; + size_t i; for(i = 0; i < array->entries; i++) json_decref(array->table[i]); - free(array->table); - free(array); + jsonp_free(array->table); + jsonp_free(array); } -unsigned int json_array_size(const json_t *json) +size_t json_array_size(const json_t *json) { if(!json_is_array(json)) return 0; @@ -388,7 +360,7 @@ unsigned int json_array_size(const json_t *json) return json_to_array(json)->entries; } -json_t *json_array_get(const json_t *json, unsigned int index) +json_t *json_array_get(const json_t *json, size_t index) { json_array_t *array; if(!json_is_array(json)) @@ -401,7 +373,7 @@ json_t *json_array_get(const json_t *json, unsigned int index) return array->table[index]; } -int json_array_set_new(json_t *json, unsigned int index, json_t *value) +int json_array_set_new(json_t *json, size_t index, json_t *value) { json_array_t *array; @@ -427,24 +399,24 @@ int json_array_set_new(json_t *json, unsigned int index, json_t *value) return 0; } -static void array_move(json_array_t *array, unsigned int dest, - unsigned int src, unsigned int count) +static void array_move(json_array_t *array, size_t dest, + size_t src, size_t count) { memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); } -static void array_copy(json_t **dest, unsigned int dpos, - json_t **src, unsigned int spos, - unsigned int count) +static void array_copy(json_t **dest, size_t dpos, + json_t **src, size_t spos, + size_t count) { memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); } static json_t **json_array_grow(json_array_t *array, - unsigned int amount, + size_t amount, int copy) { - unsigned int new_size; + size_t new_size; json_t **old_table, **new_table; if(array->entries + amount <= array->size) @@ -453,7 +425,7 @@ static json_t **json_array_grow(json_array_t *array, old_table = array->table; new_size = max(array->size + amount, array->size * 2); - new_table = malloc(new_size * sizeof(json_t *)); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); if(!new_table) return NULL; @@ -462,7 +434,7 @@ static json_t **json_array_grow(json_array_t *array, if(copy) { array_copy(array->table, 0, old_table, 0, array->entries); - free(old_table); + jsonp_free(old_table); return array->table; } @@ -494,7 +466,7 @@ int json_array_append_new(json_t *json, json_t *value) return 0; } -int json_array_insert_new(json_t *json, unsigned int index, json_t *value) +int json_array_insert_new(json_t *json, size_t index, json_t *value) { json_array_t *array; json_t **old_table; @@ -523,7 +495,7 @@ int json_array_insert_new(json_t *json, unsigned int index, json_t *value) array_copy(array->table, 0, old_table, 0, index); array_copy(array->table, index + 1, old_table, index, array->entries - index); - free(old_table); + jsonp_free(old_table); } else array_move(array, index + 1, index, array->entries - index); @@ -534,7 +506,7 @@ int json_array_insert_new(json_t *json, unsigned int index, json_t *value) return 0; } -int json_array_remove(json_t *json, unsigned int index) +int json_array_remove(json_t *json, size_t index) { json_array_t *array; @@ -547,7 +519,10 @@ int json_array_remove(json_t *json, unsigned int index) json_decref(array->table[index]); - array_move(array, index, index + 1, array->entries - index); + /* If we're removing the last element, nothing has to be moved */ + if(index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + array->entries--; return 0; @@ -556,7 +531,7 @@ int json_array_remove(json_t *json, unsigned int index) int json_array_clear(json_t *json) { json_array_t *array; - unsigned int i; + size_t i; if(!json_is_array(json)) return -1; @@ -572,7 +547,7 @@ int json_array_clear(json_t *json) int json_array_extend(json_t *json, json_t *other_json) { json_array_t *array, *other; - unsigned int i; + size_t i; if(!json_is_array(json) || !json_is_array(other_json)) return -1; @@ -593,7 +568,7 @@ int json_array_extend(json_t *json, json_t *other_json) static int json_array_equal(json_t *array1, json_t *array2) { - unsigned int i, size; + size_t i, size; size = json_array_size(array1); if(size != json_array_size(array2)) @@ -616,7 +591,7 @@ static int json_array_equal(json_t *array1, json_t *array2) static json_t *json_array_copy(json_t *array) { json_t *result; - unsigned int i; + size_t i; result = json_array(); if(!result) @@ -628,10 +603,10 @@ static json_t *json_array_copy(json_t *array) return result; } -static json_t *json_array_deep_copy(json_t *array) +static json_t *json_array_deep_copy(const json_t *array) { json_t *result; - unsigned int i; + size_t i; result = json_array(); if(!result) @@ -652,14 +627,14 @@ json_t *json_string_nocheck(const char *value) if(!value) return NULL; - string = malloc(sizeof(json_string_t)); + string = jsonp_malloc(sizeof(json_string_t)); if(!string) return NULL; json_init(&string->json, JSON_STRING); - string->value = strdup(value); + string->value = jsonp_strdup(value); if(!string->value) { - free(string); + jsonp_free(string); return NULL; } @@ -687,12 +662,15 @@ int json_string_set_nocheck(json_t *json, const char *value) char *dup; json_string_t *string; - dup = strdup(value); + if(!json_is_string(json) || !value) + return -1; + + dup = jsonp_strdup(value); if(!dup) return -1; string = json_to_string(json); - free(string->value); + jsonp_free(string->value); string->value = dup; return 0; @@ -708,8 +686,8 @@ int json_string_set(json_t *json, const char *value) static void json_delete_string(json_string_t *string) { - free(string->value); - free(string); + jsonp_free(string->value); + jsonp_free(string); } static int json_string_equal(json_t *string1, json_t *string2) @@ -717,7 +695,7 @@ static int json_string_equal(json_t *string1, json_t *string2) return strcmp(json_string_value(string1), json_string_value(string2)) == 0; } -static json_t *json_string_copy(json_t *string) +static json_t *json_string_copy(const json_t *string) { return json_string_nocheck(json_string_value(string)); } @@ -725,9 +703,9 @@ static json_t *json_string_copy(json_t *string) /*** integer ***/ -json_t *json_integer(int value) +json_t *json_integer(json_int_t value) { - json_integer_t *integer = malloc(sizeof(json_integer_t)); + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); if(!integer) return NULL; json_init(&integer->json, JSON_INTEGER); @@ -736,7 +714,7 @@ json_t *json_integer(int value) return &integer->json; } -int json_integer_value(const json_t *json) +json_int_t json_integer_value(const json_t *json) { if(!json_is_integer(json)) return 0; @@ -744,7 +722,7 @@ int json_integer_value(const json_t *json) return json_to_integer(json)->value; } -int json_integer_set(json_t *json, int value) +int json_integer_set(json_t *json, json_int_t value) { if(!json_is_integer(json)) return -1; @@ -756,7 +734,7 @@ int json_integer_set(json_t *json, int value) static void json_delete_integer(json_integer_t *integer) { - free(integer); + jsonp_free(integer); } static int json_integer_equal(json_t *integer1, json_t *integer2) @@ -764,7 +742,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2) return json_integer_value(integer1) == json_integer_value(integer2); } -static json_t *json_integer_copy(json_t *integer) +static json_t *json_integer_copy(const json_t *integer) { return json_integer(json_integer_value(integer)); } @@ -774,7 +752,12 @@ static json_t *json_integer_copy(json_t *integer) json_t *json_real(double value) { - json_real_t *real = malloc(sizeof(json_real_t)); + json_real_t *real; + + if(isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); if(!real) return NULL; json_init(&real->json, JSON_REAL); @@ -793,8 +776,8 @@ double json_real_value(const json_t *json) int json_real_set(json_t *json, double value) { - if(!json_is_real(json)) - return 0; + if(!json_is_real(json) || isnan(value) || isinf(value)) + return -1; json_to_real(json)->value = value; @@ -803,7 +786,7 @@ int json_real_set(json_t *json, double value) static void json_delete_real(json_real_t *real) { - free(real); + jsonp_free(real); } static int json_real_equal(json_t *real1, json_t *real2) @@ -811,7 +794,7 @@ static int json_real_equal(json_t *real1, json_t *real2) return json_real_value(real1) == json_real_value(real2); } -static json_t *json_real_copy(json_t *real) +static json_t *json_real_copy(const json_t *real) { return json_real(json_real_value(real)); } @@ -822,7 +805,7 @@ static json_t *json_real_copy(json_t *real) double json_number_value(const json_t *json) { if(json_is_integer(json)) - return json_integer_value(json); + return (double)json_integer_value(json); else if(json_is_real(json)) return json_real_value(json); else @@ -834,30 +817,21 @@ double json_number_value(const json_t *json) json_t *json_true(void) { - static json_t the_true = { - .type = JSON_TRUE, - .refcount = (unsigned int)-1 - }; + static json_t the_true = {JSON_TRUE, (size_t)-1}; return &the_true; } json_t *json_false(void) { - static json_t the_false = { - .type = JSON_FALSE, - .refcount = (unsigned int)-1 - }; + static json_t the_false = {JSON_FALSE, (size_t)-1}; return &the_false; } json_t *json_null(void) { - static json_t the_null = { - .type = JSON_NULL, - .refcount = (unsigned int)-1 - }; + static json_t the_null = {JSON_NULL, (size_t)-1}; return &the_null; } @@ -946,7 +920,7 @@ json_t *json_copy(json_t *json) return NULL; } -json_t *json_deep_copy(json_t *json) +json_t *json_deep_copy(const json_t *json) { if(!json) return NULL; @@ -970,7 +944,7 @@ json_t *json_deep_copy(json_t *json) return json_real_copy(json); if(json_is_true(json) || json_is_false(json) || json_is_null(json)) - return json; + return (json_t *)json; return NULL; } diff --git a/compat/pthreads/pthread.h b/compat/pthreads/pthread.h new file mode 100644 index 000000000..85f9cceee --- /dev/null +++ b/compat/pthreads/pthread.h @@ -0,0 +1,1372 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +// undef for DLLs +#define PTW32_STATIC_LIB + + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,9,1,0 +#define PTW32_VERSION_STRING "2, 9, 1, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#if !defined(RC_INVOKED) + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if defined(_UWIN) +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_PTW32_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if (defined(__MINGW64__) || defined(__MINGW32__)) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#if defined(PTW32_INCLUDE_WINDOWS_H) +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +typedef unsigned long ULONG_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if defined(HAVE_PTW32_CONFIG_H) +#include "config.h" +#endif /* HAVE_PTW32_CONFIG_H */ + +#if !defined(NEED_FTIME) +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if defined(HAVE_SIGNAL_H) +#include +#endif /* HAVE_SIGNAL_H */ + +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#if !defined(ENOTSUP) +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#if !defined(ETIMEDOUT) +# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ +#endif + +#if !defined(ENOSYS) +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#if !defined(EDEADLK) +# if defined(EDEADLOCK) +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +/* POSIX 2008 - related to robust mutexes */ +#if !defined(EOWNERDEAD) +# define EOWNERDEAD 43 +#endif +#if !defined(ENOTRECOVERABLE) +# define ENOTRECOVERABLE 44 +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#if !defined(PTW32_INCLUDE_WINDOWS_H) +#if !defined(HANDLE) +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#if !defined(DWORD) +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#if !defined(HAVE_STRUCT_TIMESPEC) +#define HAVE_STRUCT_TIMESPEC +#if !defined(_TIMESPEC_DEFINED) +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif /* _TIMESPEC_DEFINED */ +#endif /* HAVE_STRUCT_TIMESPEC */ + +#if !defined(SIG_BLOCK) +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#if !defined(SIG_UNBLOCK) +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#if !defined(SIG_SETMASK) +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200809L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200809L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200809L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200809L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200809L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if defined(__GNUC__) && !defined(__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_mutexattr_{get,set}robust + */ + PTHREAD_MUTEX_STALLED = 0, /* Default */ + PTHREAD_MUTEX_ROBUST = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *)(size_t) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#if defined(__CLEANUP_SEH) + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_C) + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#if defined(__CLEANUP_CXX) + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(PTW32_CDECL *start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (PTW32_CDECL *init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + ptw32_cleanup_callback_t routine, + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (PTW32_CDECL *destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( + pthread_mutexattr_t *attr, + int robust); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( + const pthread_mutexattr_t * attr, + int * robust); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); +PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); +/* + * Returns the win32 thread ID for POSIX thread. + */ +PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#if !defined(_UWIN) +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# if !defined(errno) +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#if defined(__cplusplus) + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if !defined(PTW32_BUILD) + +#if defined(__CLEANUP_SEH) + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_CXX) + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#if defined(_MSC_VER) + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#if !defined(PtW32NoCatchWarn) + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #if defined(PtW32CatchAll)") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#if defined(PTW32__HANDLE_DEF) +# undef HANDLE +#endif +#if defined(PTW32__DWORD_DEF) +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/compat/pthreads/sched.h b/compat/pthreads/sched.h new file mode 100644 index 000000000..f36a97a66 --- /dev/null +++ b/compat/pthreads/sched.h @@ -0,0 +1,183 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(_SCHED_H) +#define _SCHED_H + +#undef PTW32_SCHED_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_SCHED_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_SCHED_LEVEL +#define PTW32_SCHED_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_SCHED_LEVEL +#define PTW32_SCHED_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_SCHED_LEVEL_MAX 3 + +#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) +#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX +/* Include everything */ +#endif + + +#if defined(__GNUC__) && !defined(__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ + +#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) +# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +# else + typedef int pid_t; +# endif +#else + typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_SCHED_LEVEL +#undef PTW32_SCHED_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/compat/pthreads/x64/libpthreadGC2.a b/compat/pthreads/x64/libpthreadGC2.a new file mode 100644 index 000000000..9ce81325b Binary files /dev/null and b/compat/pthreads/x64/libpthreadGC2.a differ diff --git a/compat/pthreads/x64/pthreadVC2.lib b/compat/pthreads/x64/pthreadVC2.lib new file mode 100644 index 000000000..3e26e4a06 Binary files /dev/null and b/compat/pthreads/x64/pthreadVC2.lib differ diff --git a/compat/pthreads/x86/pthreadVC2.lib b/compat/pthreads/x86/pthreadVC2.lib new file mode 100644 index 000000000..5880478f9 Binary files /dev/null and b/compat/pthreads/x86/pthreadVC2.lib differ diff --git a/compat/stdbool.h b/compat/stdbool.h new file mode 100644 index 000000000..3def25f93 --- /dev/null +++ b/compat/stdbool.h @@ -0,0 +1,6 @@ +#pragma once + +#define false 0 +#define true 1 + +#define bool int diff --git a/compat/sys/time.h b/compat/sys/time.h new file mode 100644 index 000000000..9d26a63ee --- /dev/null +++ b/compat/sys/time.h @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif +int gettimeofday(struct timeval *tv, struct timezone *tz); +void usleep(__int64 usec); +#ifdef __cplusplus +} +#endif +typedef __int64 useconds_t; diff --git a/compat/unistd.h b/compat/unistd.h new file mode 100644 index 000000000..b0690f96e --- /dev/null +++ b/compat/unistd.h @@ -0,0 +1,2 @@ +#pragma once +#include "getopt/getopt.h" \ No newline at end of file diff --git a/compat/winansi.c b/compat/winansi.c new file mode 100644 index 000000000..50e8388ac --- /dev/null +++ b/compat/winansi.c @@ -0,0 +1,392 @@ +/** + * Old Git implementation of windows terminal colors (2009) + * before use of a threaded wrapper. + */ + +#undef NOGDI +#include +#include +#include +#include +#include +#include + +#include "compat/winansi.h" +/* +* Copyright 2008 Peter Harris +*/ + +/* +Functions to be wrapped: +*/ +#undef printf +#undef fprintf +#undef fputs +#undef vfprintf +/* TODO: write */ + +/* +ANSI codes used by git: m, K + +This file is git-specific. Therefore, this file does not attempt +to implement any codes that are not used by git. +*/ + +static HANDLE console; +static WORD plain_attr; +static WORD attr; +static int negative; + +static void init(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + static int initialized = 0; + if (initialized) + return; + + console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) + console = NULL; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + attr = plain_attr = sbi.wAttributes; + negative = 0; + + initialized = 1; +} + +static int write_console(const char *str, int len) +{ + /* convert utf-8 to utf-16, write directly to console */ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + wchar_t *wbuf = (wchar_t *)alloca(wlen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen); + + WriteConsoleW(console, wbuf, wlen, NULL, NULL); + + /* return original (utf-8 encoded) length */ + return len; +} + +#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) + +static void set_console_attr(void) +{ + WORD attributes = attr; + if (negative) { + attributes &= ~FOREGROUND_ALL; + attributes &= ~BACKGROUND_ALL; + + /* This could probably use a bitmask + instead of a series of ifs */ + if (attr & FOREGROUND_RED) + attributes |= BACKGROUND_RED; + if (attr & FOREGROUND_GREEN) + attributes |= BACKGROUND_GREEN; + if (attr & FOREGROUND_BLUE) + attributes |= BACKGROUND_BLUE; + + if (attr & BACKGROUND_RED) + attributes |= FOREGROUND_RED; + if (attr & BACKGROUND_GREEN) + attributes |= FOREGROUND_GREEN; + if (attr & BACKGROUND_BLUE) + attributes |= FOREGROUND_BLUE; + } + SetConsoleTextAttribute(console, attributes); +} + +static void erase_in_line(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + DWORD dummy; /* Needed for Windows 7 (or Vista) regression */ + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + FillConsoleOutputCharacterA(console, ' ', + sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, + &dummy); +} + + +static const char *set_attr(const char *str) +{ + const char *func; + size_t len = strspn(str, "0123456789;"); + func = str + len; + + switch (*func) { + case 'm': + do { + long val = strtol(str, (char **)&str, 10); + switch (val) { + case 0: /* reset */ + attr = plain_attr; + negative = 0; + break; + case 1: /* bold */ + attr |= FOREGROUND_INTENSITY; + break; + case 2: /* faint */ + case 22: /* normal */ + attr &= ~FOREGROUND_INTENSITY; + break; + case 3: /* italic */ + /* Unsupported */ + break; + case 4: /* underline */ + case 21: /* double underline */ + /* Wikipedia says this flag does nothing */ + /* Furthermore, mingw doesn't define this flag + attr |= COMMON_LVB_UNDERSCORE; */ + break; + case 24: /* no underline */ + /* attr &= ~COMMON_LVB_UNDERSCORE; */ + break; + case 5: /* slow blink */ + case 6: /* fast blink */ + /* We don't have blink, but we do have + background intensity */ + attr |= BACKGROUND_INTENSITY; + break; + case 25: /* no blink */ + attr &= ~BACKGROUND_INTENSITY; + break; + case 7: /* negative */ + negative = 1; + break; + case 27: /* positive */ + negative = 0; + break; + case 8: /* conceal */ + case 28: /* reveal */ + /* Unsupported */ + break; + case 30: /* Black */ + attr &= ~FOREGROUND_ALL; + break; + case 31: /* Red */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED; + break; + case 32: /* Green */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN; + break; + case 33: /* Yellow */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* Blue */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_BLUE; + break; + case 35: /* Magenta */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* Cyan */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 37: /* White */ + attr |= FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE; + break; + case 38: /* Unknown */ + break; + case 39: /* reset */ + attr &= ~FOREGROUND_ALL; + attr |= (plain_attr & FOREGROUND_ALL); + break; + case 40: /* Black */ + attr &= ~BACKGROUND_ALL; + break; + case 41: /* Red */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED; + break; + case 42: /* Green */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN; + break; + case 43: /* Yellow */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* Blue */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_BLUE; + break; + case 45: /* Magenta */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* Cyan */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 47: /* White */ + attr |= BACKGROUND_RED | + BACKGROUND_GREEN | + BACKGROUND_BLUE; + break; + case 48: /* Unknown */ + break; + case 49: /* reset */ + attr &= ~BACKGROUND_ALL; + attr |= (plain_attr & BACKGROUND_ALL); + break; + default: + /* Unsupported code */ + break; + } + str++; + } while (*(str - 1) == ';'); + + set_console_attr(); + break; + case 'K': + erase_in_line(); + break; + default: + /* Unsupported code */ + break; + } + + return func + 1; +} + +static int ansi_emulate(const char *str, FILE *stream) +{ + int rv = 0; + const char *pos = str; + + fflush(stream); + + while (*pos) { + pos = strstr(str, "\033["); + if (pos) { + int len = (int) (pos - str); + + if (len) { + int out_len = write_console(str, len); + rv += out_len; + if (out_len < len) + return rv; + } + + str = pos + 2; + rv += 2; + + pos = set_attr(str); + rv += (int) (pos - str); + str = pos; + } + else { + int len = (int) strlen(str); + rv += write_console(str, len); + return rv; + } + } + return rv; +} + +int winansi_fputs(const char *str, FILE *stream) +{ + int rv; + + if (!isatty(fileno(stream))) + return fputs(str, stream); + + init(); + + if (!console) + return fputs(str, stream); + + rv = ansi_emulate(str, stream); + + if (rv >= 0) + return 0; + else + return EOF; +} + +int winansi_vfprintf(FILE *stream, const char *format, va_list list) +{ + int len, rv; + char small_buf[256] = { 0 }; + char *buf = small_buf; + va_list cp; + + if (!isatty(fileno(stream))) + goto abort; + + init(); + + if (!console) + goto abort; + + va_copy(cp, list); + len = vsnprintf(small_buf, sizeof(small_buf), format, cp); +#ifdef WIN32 + /* bug on long strings without that */ + if (len == -1) + len = _vscprintf(format, cp); +#endif + va_end(cp); + + if (len > sizeof(small_buf) - 1) { + buf = malloc(len + 1); + if (!buf) + goto abort; + + len = vsnprintf(buf, len + 1, format, list); +#ifdef WIN32 + if (len == -1) + len = _vscprintf(format, list); +#endif + } + + rv = ansi_emulate(buf, stream); + + if (buf != small_buf) + free(buf); + return rv; + +abort: + rv = vfprintf(stream, format, list); + return rv; +} + +int winansi_fprintf(FILE *stream, const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stream, format, list); + va_end(list); + + return rv; +} + +int winansi_printf(const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stdout, format, list); + va_end(list); + + return rv; +} \ No newline at end of file diff --git a/compat/winansi.h b/compat/winansi.h new file mode 100644 index 000000000..c28dd15cd --- /dev/null +++ b/compat/winansi.h @@ -0,0 +1,32 @@ +/* + * ANSI emulation wrappers + */ +#ifdef WIN32 +#include +#include +#include + +#define isatty(fd) _isatty(fd) +#define fileno(fd) _fileno(fd) + +#ifdef __cplusplus +extern "C" { +#endif + int winansi_fputs(const char *str, FILE *stream); + int winansi_printf(const char *format, ...); + int winansi_fprintf(FILE *stream, const char *format, ...); + int winansi_vfprintf(FILE *stream, const char *format, va_list list); +#ifdef __cplusplus +} +#endif + +#undef fputs +#undef fprintf +#undef vfprintf + +#define fputs winansi_fputs +#define printf winansi_printf +#define fprintf winansi_fprintf +#define vfprintf winansi_vfprintf + +#endif \ No newline at end of file diff --git a/configure.ac b/configure.ac index ae81b2e30..d9738dec5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,12 @@ -AC_INIT([cpuminer], [1.0.4]) +AC_INIT([cpuminer-multi], [1.3.7]) AC_PREREQ([2.59c]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([cpu-miner.c]) -AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_HEADERS([cpuminer-config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([foreign subdir-objects]) dnl Make sure anyone changing configure.ac/Makefile.am has a clue AM_MAINTAINER_MODE @@ -15,6 +17,7 @@ AC_PROG_GCC_TRADITIONAL AM_PROG_CC_C_O AM_PROG_AS AC_PROG_RANLIB +AC_PROG_CXX dnl Checks for header files AC_HEADER_STDC @@ -28,7 +31,7 @@ AC_CHECK_HEADERS([sys/sysctl.h], [], [], #endif ]) -AC_CHECK_DECLS([be32dec, le32dec, be32enc, le32enc], [], [], +AC_CHECK_DECLS([be32dec, le32dec, be32enc, le32enc, le16dec, le16enc], [], [], [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_ENDIAN_H #include @@ -38,27 +41,35 @@ AC_CHECK_DECLS([be32dec, le32dec, be32enc, le32enc], [], [], AC_FUNC_ALLOCA AC_CHECK_FUNCS([getopt_long]) -case $target in - i*86-*-*) - have_x86=true - ;; - x86_64-*-*|amd64-*-*) - have_x86_64=true - ;; +MINGW_TARGET=`$CC -dumpmachine 2>&1` +case $MINGW_TARGET in arm*-*-*) have_arm=true ;; -esac - -PTHREAD_FLAGS="-pthread" -WS2_LIBS="" - -case $target in - *-*-mingw*) + aarch64*-*-*) + have_arm=true + ;; + i*86-*-mingw*) + have_x86=true have_win32=true - PTHREAD_FLAGS="" + CFLAGS="-Icompat/pthreads $CFLAGS" + PTHREAD_LDFLAGS="-Lcompat/pthreads/x86" WS2_LIBS="-lws2_32" ;; + x86_64-*-mingw*|amd64-*-mingw*) + have_x86_64=true + have_win32=true + CFLAGS="-Icompat/pthreads $CFLAGS" + PTHREAD_LDFLAGS="-Lcompat/pthreads/x64" + # SHOULD BE AT END! after -lcrypto # + WS2_LIBS="-L/mingw/x86_64-w64-mingw32/lib -lws2_32" + ;; + i*86-*-*) + have_x86=true + ;; + x86_64-*-*|amd64-*-*) + have_x86_64=true + ;; esac AC_ARG_ENABLE([assembly], @@ -96,13 +107,17 @@ then fi AC_CHECK_LIB(jansson, json_loads, request_jansson=false, request_jansson=true) -AC_CHECK_LIB([pthread], [pthread_create], PTHREAD_LIBS="-lpthread", - AC_CHECK_LIB([pthreadGC2], [pthread_create], PTHREAD_LIBS="-lpthreadGC2", - AC_CHECK_LIB([pthreadGC1], [pthread_create], PTHREAD_LIBS="-lpthreadGC1", - AC_CHECK_LIB([pthreadGC], [pthread_create], PTHREAD_LIBS="-lpthreadGC" -)))) -AC_CHECK_LIB([crypto], [OPENSSL_init], [], [AC_MSG_FAILURE([could not find crypto])]) +# GC2 for GNU static +if test "x$OS" = "xWindows_NT" ; then + # MinGW + AC_CHECK_LIB([pthread], [pthread_create], PTHREAD_LIBS="-lpthreadGC2",[]) +else + AC_CHECK_LIB([pthread], [pthread_create], PTHREAD_LIBS="-lpthread",[]) +fi + +LDFLAGS="$PTHREAD_LDFLAGS $LDFLAGS" +# PTHREAD_LIBS="$PTHREAD_LIBS" AC_MSG_CHECKING(whether __uint128_t is supported) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([static __uint128_t i = 100;])], @@ -112,22 +127,62 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([static __uint128_t i = 100;])], AC_MSG_RESULT(no) ) +# allow if in Makefile.am AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([USE_ASM], [test x$enable_assembly != xno]) AM_CONDITIONAL([ARCH_x86], [test x$have_x86 = xtrue]) AM_CONDITIONAL([ARCH_x86_64], [test x$have_x86_64 = xtrue]) AM_CONDITIONAL([ARCH_ARM], [test x$have_arm = xtrue]) +AM_CONDITIONAL([MINGW], [test "x$OS" = "xWindows_NT"]) -if test x$request_jansson = xtrue -then +if test x$request_jansson = xtrue ; then JANSSON_LIBS="compat/jansson/libjansson.a" else JANSSON_LIBS=-ljansson fi -LIBCURL_CHECK_CONFIG(, 7.15.2, , - [AC_MSG_ERROR([Missing required libcurl >= 7.15.2])]) +# libcurl install path (for mingw : --with-curl=/usr/local) +AC_ARG_WITH([curl], + [ --with-curl=PATH prefix where curl is installed [default=/usr]]) + +if test -n "$with_curl" ; then + LIBCURL_CFLAGS="$LIBCURL_CFLAGS -I$with_curl/include" + LIBCURL_CPPFLAGS="$LIBCURL_CPPFLAGS -I$with_curl/include" + LIBCURL_LDFLAGS="-L$with_curl/lib $LIBCURL_LDFLAGS" + LIBCURL="-lcurl -lz" +fi + +# SSL install path (for mingw : --with-crypto=/usr/local/ssl) +AC_ARG_WITH([crypto], + [ --with-crypto=PATH prefix where openssl crypto is installed [default=/usr]]) + +if test -n "$with_crypto" ; then + LIBCURL_CFLAGS="$LIBCURL_CFLAGS -I$with_crypto/include" + LIBCURL_CPPFLAGS="$LIBCURL_CPPFLAGS -I$with_crypto/include" + LIBCURL_LDFLAGS="-L$with_crypto/lib $LIBCURL_LDFLAGS" + LIBCURL="$LIBCURL -lssl -lcrypto" +fi + +CFLAGS="$CFLAGS $LIBCURL_CFLAGS" +CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" +LDFLAGS="$LDFLAGS $LIBCURL_LDFLAGS" + +AC_CHECK_LIB([z],[gzopen],[],[]) +AC_CHECK_LIB([crypto],[EVP_DigestFinal_ex], crypto=yes, [AC_MSG_ERROR([OpenSSL crypto library required])]) +AC_CHECK_LIB([ssl],[SSL_free], ssl=yes, ssl=no) + +# AC_CHECK_LIB([curl], [curl_multi_timeout], +# have_libcurl=yes, +# have_libcurl=no AC_MSG_ERROR([curl library required]) +# ) + +# LIBCURL_CHECK_CONFIG([yes], 7.15, curlconfig=yes, curlconfig=no) + +AC_SUBST(LIBCURL) +AC_SUBST(LIBCURL_CFLAGS) +AC_SUBST(LIBCURL_CPPFLAGS) +# AC_SUBST(LIBCURL_LDFLAGS) AC_SUBST(JANSSON_LIBS) AC_SUBST(PTHREAD_FLAGS) diff --git a/cpu-miner.c b/cpu-miner.c index 608c5ecf6..5e8948d80 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -2,6 +2,7 @@ * Copyright 2010 Jeff Garzik * Copyright 2012-2014 pooler * Copyright 2014 Lucas Jones + * Copyright 2014 Tanguy Pruvot * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -9,7 +10,7 @@ * any later version. See COPYING for more details. */ -#include "cpuminer-config.h" +#include #define _GNU_SOURCE #include @@ -20,12 +21,17 @@ #include #include #include -#ifdef WIN32 +#include + +#include +#include +#include + +#ifdef _MSC_VER #include +#include #else #include -#include -#include #if HAVE_SYS_SYSCTL_H #include #if HAVE_SYS_PARAM_H @@ -34,187 +40,352 @@ #include #endif #endif -#include -#include -#include "compat.h" -#include "miner.h" -#define PROGRAM_NAME "minerd" -#define LP_SCANTIME 60 -#define JSON_BUF_LEN 345 +#ifndef WIN32 +#include +#endif -#ifdef __linux /* Linux specific policy and affinity management */ -#include -static inline void drop_policy(void) { - struct sched_param param; - param.sched_priority = 0; +#include "miner.h" -#ifdef SCHED_IDLE - if (unlikely(sched_setscheduler(0, SCHED_IDLE, ¶m) == -1)) +#ifdef WIN32 +#include "compat/winansi.h" +BOOL WINAPI ConsoleHandler(DWORD); #endif -#ifdef SCHED_BATCH - sched_setscheduler(0, SCHED_BATCH, ¶m); +#ifdef _MSC_VER +#include +#pragma comment(lib, "winmm.lib") #endif -} - -static inline void affine_to_cpu(int id, int cpu) { - cpu_set_t set; - - CPU_ZERO(&set); - CPU_SET(cpu, &set); - sched_setaffinity(0, sizeof(set), &set); -} -#elif defined(__FreeBSD__) /* FreeBSD specific policy and affinity management */ -#include -static inline void drop_policy(void) -{ -} -static inline void affine_to_cpu(int id, int cpu) -{ - cpuset_t set; - CPU_ZERO(&set); - CPU_SET(cpu, &set); - cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &set); -} -#else -static inline void drop_policy(void) -{ -} +#define LP_SCANTIME 60 -static inline void affine_to_cpu(int id, int cpu) -{ -} +#ifndef min +#define min(a,b) (a>b ? b : a) +#define max(a,b) (a #else struct option { - const char *name; - int has_arg; - int *flag; - int val; + const char *name; + int has_arg; + int *flag; + int val; }; #endif -static char const usage[] = - "\ -Usage: " PROGRAM_NAME " [OPTIONS]\n\ +static char const usage[] = "\ +Usage: " PACKAGE_NAME " [OPTIONS]\n\ Options:\n\ -a, --algo=ALGO specify the algorithm to use\n\ + allium Garlicoin double lyra2\n\ + axiom Shabal-256 MemoHash\n\ + bitcore Timetravel with 10 algos\n\ + blake Blake-256 14-rounds (SFR)\n\ + blakecoin Blake-256 single sha256 merkle\n\ + blake2b Blake2-B (512)\n\ + blake2s Blake2-S (256)\n\ + bmw BMW 256\n\ + c11/flax C11\n\ + cryptolight Cryptonight-light\n\ + cryptonight Monero\n\ + decred Blake-256 14-rounds 180 bytes\n\ + dmd-gr Diamond-Groestl\n\ + drop Dropcoin\n\ + fresh Fresh\n\ + geek GeekCash\n\ + groestl GroestlCoin\n\ + heavy Heavy\n\ + jha JHA\n\ + keccak Keccak (Old and deprecated)\n\ + keccakc Keccak (CreativeCoin)\n\ + luffa Luffa\n\ + lyra2re Lyra2RE\n\ + lyra2rev2 Lyra2REv2\n\ + lyra2v3 Lyra2REv3 (Vertcoin)\n\ + myr-gr Myriad-Groestl\n\ + neoscrypt NeoScrypt(128, 2, 1)\n\ + nist5 Nist5\n\ + pluck Pluck:128 (Supcoin)\n\ + pentablake Pentablake\n\ + phi LUX initial algo\n\ + phi2 LUX newer algo\n\ + quark Quark\n\ + qubit Qubit\n\ + rainforest RainForest (256)\n\ scrypt scrypt(1024, 1, 1) (default)\n\ scrypt:N scrypt(N, 1, 1)\n\ - sha256d SHA-256d\n\ - keccak Keccak\n\ - quark Quark\n\ - heavy Heavy\n\ - skein Skein\n\ + scrypt-jane:N (with N factor from 4 to 30)\n\ shavite3 Shavite3\n\ - blake Blake\n\ - fresh Fresh\n\ + sha256d SHA-256d\n\ + sia Blake2-B\n\ + sib X11 + gost (SibCoin)\n\ + skein Skein+Sha (Skeincoin)\n\ + skein2 Double Skein (Woodcoin)\n\ + sonoa A series of 97 hashes from x17\n\ + s3 S3\n\ + timetravel Timetravel (Machinecoin)\n\ + vanilla Blake-256 8-rounds\n\ + x11evo Permuted x11\n\ x11 X11\n\ + x12 X12\n\ x13 X13\n\ x14 X14\n\ x15 X15\n\ - cryptonight CryptoNight\n\ + x16r X16R\n\ + x16rv2 X16Rv2 (Raven / Trivechain)\n\ + x16s X16S (Pigeon)\n\ + x17 X17\n\ + x20r X20R\n\ + xevan Xevan (BitSend)\n\ + yescrypt Yescrypt\n\ + yescryptr8 Yescrypt r8\n\ + yescryptr16 Yescrypt r16\n\ + yescryptr32 Yescrypt r32\n\ + zr5 ZR5\n\ -o, --url=URL URL of mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\ -u, --user=USERNAME username for mining server\n\ @@ -225,1307 +396,2513 @@ Options:\n\ -r, --retries=N number of times to retry if a network call fails\n\ (default: retry indefinitely)\n\ -R, --retry-pause=N time to pause between retries, in seconds (default: 30)\n\ - -T, --timeout=N timeout for long polling, in seconds (default: none)\n\ + --time-limit=N maximum time [s] to mine before exiting the program.\n\ + -T, --timeout=N timeout for long poll and stratum (default: 300 seconds)\n\ -s, --scantime=N upper bound on time spent scanning current work when\n\ long polling is unavailable, in seconds (default: 5)\n\ - --no-longpoll disable X-Long-Polling support\n\ + --randomize Randomize scan range start to reduce duplicates\n\ + -f, --diff-factor Divide req. difficulty by this factor (std is 1.0)\n\ + -m, --diff-multiplier Multiply difficulty by this factor (std is 1.0)\n\ + -n, --nfactor neoscrypt N-Factor\n\ + --coinbase-addr=ADDR payout address for solo mining\n\ + --coinbase-sig=TEXT data to insert in the coinbase when possible\n\ + --max-log-rate limit per-core hashrate logs (default: 5s)\n\ + --no-longpoll disable long polling support\n\ + --no-getwork disable getwork support\n\ + --no-gbt disable getblocktemplate support\n\ --no-stratum disable X-Stratum support\n\ + --no-extranonce disable Stratum extranonce support\n\ --no-redirect ignore requests to change the URL of the mining server\n\ -q, --quiet disable per-thread hashmeter output\n\ + --no-color disable colored output\n\ -D, --debug enable debug output\n\ - -P, --protocol-dump verbose dump of protocol-level activities\n" + -P, --protocol-dump verbose dump of protocol-level activities\n\ + --hide-diff Hide submitted block and net difficulty\n" #ifdef HAVE_SYSLOG_H - "\ +"\ -S, --syslog use system log for output messages\n" #endif -#ifndef WIN32 - "\ - -B, --background run the miner in the background\n" -#endif - "\ +"\ + -B, --background run the miner in the background\n\ --benchmark run in offline benchmark mode\n\ + --cputest debug hashes from cpu algorithms\n\ + --cpu-affinity set process affinity to cpu core(s), mask 0x3 for cores 0 and 1\n\ + --cpu-priority set process priority (default: 0 idle, 2 normal to 5 highest)\n\ + -b, --api-bind IP/Port for the miner API (default: 127.0.0.1:4048)\n\ + --api-remote Allow remote control\n\ + --max-temp=N Only mine if cpu temp is less than specified value (linux)\n\ + --max-rate=N[KMG] Only mine if net hashrate is less than specified value\n\ + --max-diff=N Only mine if net difficulty is less than specified value\n\ -c, --config=FILE load a JSON-format configuration file\n\ -V, --version display version information and exit\n\ -h, --help display this help text and exit\n\ "; + static char const short_options[] = -#ifndef WIN32 - "B" -#endif #ifdef HAVE_SYSLOG_H - "S" + "S" #endif - "a:c:Dhp:Px:qr:R:s:t:T:o:u:O:V"; + "a:b:Bc:CDf:hm:n:p:Px:qr:R:s:t:T:o:u:O:V"; static struct option const options[] = { - { "algo", 1, NULL, 'a' }, -#ifndef WIN32 - { "background", 0, NULL, 'B' }, -#endif - { "benchmark", 0, NULL, 1005 }, - { "cert", 1, NULL, 1001 }, - { "config", 1, NULL, 'c' }, - { "debug", 0, NULL, 'D' }, - { "help", 0, NULL, 'h' }, - { "no-longpoll", 0, NULL, 1003 }, - { "no-redirect", 0, NULL, 1009 }, - { "no-stratum", 0, NULL, 1007 }, - { "pass", 1, NULL, 'p' }, - { "protocol-dump", 0, NULL, 'P' }, - { "proxy", 1, NULL, 'x' }, - { "quiet", 0, NULL, 'q' }, - { "retries", 1, NULL, 'r' }, - { "retry-pause", 1, NULL, 'R' }, - { "scantime", 1, NULL, 's' }, + { "algo", 1, NULL, 'a' }, + { "api-bind", 1, NULL, 'b' }, + { "api-remote", 0, NULL, 1030 }, + { "background", 0, NULL, 'B' }, + { "benchmark", 0, NULL, 1005 }, + { "cputest", 0, NULL, 1006 }, + { "cert", 1, NULL, 1001 }, + { "coinbase-addr", 1, NULL, 1016 }, + { "coinbase-sig", 1, NULL, 1015 }, + { "config", 1, NULL, 'c' }, + { "cpu-affinity", 1, NULL, 1020 }, + { "cpu-priority", 1, NULL, 1021 }, + { "no-color", 0, NULL, 1002 }, + { "debug", 0, NULL, 'D' }, + { "diff-factor", 1, NULL, 'f' }, + { "diff", 1, NULL, 'f' }, // deprecated (alias) + { "diff-multiplier", 1, NULL, 'm' }, + { "help", 0, NULL, 'h' }, + { "nfactor", 1, NULL, 'n' }, + { "no-gbt", 0, NULL, 1011 }, + { "no-getwork", 0, NULL, 1010 }, + { "no-longpoll", 0, NULL, 1003 }, + { "no-redirect", 0, NULL, 1009 }, + { "no-stratum", 0, NULL, 1007 }, + { "no-extranonce", 0, NULL, 1012 }, + { "max-temp", 1, NULL, 1060 }, + { "max-diff", 1, NULL, 1061 }, + { "max-rate", 1, NULL, 1062 }, + { "pass", 1, NULL, 'p' }, + { "protocol", 0, NULL, 'P' }, + { "protocol-dump", 0, NULL, 'P' }, + { "proxy", 1, NULL, 'x' }, + { "quiet", 0, NULL, 'q' }, + { "retries", 1, NULL, 'r' }, + { "retry-pause", 1, NULL, 'R' }, + { "randomize", 0, NULL, 1024 }, + { "scantime", 1, NULL, 's' }, + { "show-diff", 0, NULL, 1013 }, + { "hide-diff", 0, NULL, 1014 }, + { "max-log-rate", 1, NULL, 1019 }, #ifdef HAVE_SYSLOG_H - { "syslog", 0, NULL, 'S' }, + { "syslog", 0, NULL, 'S' }, #endif - { "threads", 1, NULL, 't' }, - { "timeout", 1, NULL, 'T' }, - { "url", 1, NULL, 'o' }, - { "user", 1, NULL, 'u' }, - { "userpass", 1, NULL, 'O' }, - { "version", 0, NULL, 'V' }, - { 0, 0, 0, 0 } + { "time-limit", 1, NULL, 1008 }, + { "threads", 1, NULL, 't' }, + { "timeout", 1, NULL, 'T' }, + { "url", 1, NULL, 'o' }, + { "user", 1, NULL, 'u' }, + { "userpass", 1, NULL, 'O' }, + { "version", 0, NULL, 'V' }, + { 0, 0, 0, 0 } }; -static struct work g_work; -static time_t g_work_time; +static struct work g_work = {{ 0 }}; +static time_t g_work_time = 0; static pthread_mutex_t g_work_lock; +static bool submit_old = false; +static char *lp_id; -static bool rpc2_login(CURL *curl); static void workio_cmd_free(struct workio_cmd *wc); -json_t *json_rpc2_call_recur(CURL *curl, const char *url, - const char *userpass, json_t *rpc_req, - int *curl_err, int flags, int recur) { - if(recur >= 5) { - if(opt_debug) - applog(LOG_DEBUG, "Failed to call rpc command after %i tries", recur); - return NULL; - } - if(!strcmp(rpc2_id, "")) { - if(opt_debug) - applog(LOG_DEBUG, "Tried to call rpc2 command before authentication"); - return NULL; + +#ifdef __linux /* Linux specific policy and affinity management */ +#include + +static inline void drop_policy(void) +{ + struct sched_param param; + param.sched_priority = 0; +#ifdef SCHED_IDLE + if (unlikely(sched_setscheduler(0, SCHED_IDLE, ¶m) == -1)) +#endif +#ifdef SCHED_BATCH + sched_setscheduler(0, SCHED_BATCH, ¶m); +#endif +} + +#ifdef __BIONIC__ +#define pthread_setaffinity_np(tid,sz,s) {} /* only do process affinity */ +#endif + +static void affine_to_cpu_mask(int id, unsigned long mask) { + cpu_set_t set; + CPU_ZERO(&set); + for (uint8_t i = 0; i < num_cpus; i++) { + // cpu mask + if (mask & (1UL<job_id); - free(w->xnonce2); +void get_currentalgo(char* buf, int sz) +{ + if (opt_algo == ALGO_SCRYPTJANE) + snprintf(buf, sz, "%s:%d", algo_names[opt_algo], opt_scrypt_n); + else + snprintf(buf, sz, "%s", algo_names[opt_algo]); } -static inline void work_copy(struct work *dest, const struct work *src) { - memcpy(dest, src, sizeof(struct work)); - if (src->job_id) - dest->job_id = strdup(src->job_id); - if (src->xnonce2) { - dest->xnonce2 = malloc(src->xnonce2_len); - memcpy(dest->xnonce2, src->xnonce2, src->xnonce2_len); - } +void proper_exit(int reason) +{ +#ifdef WIN32 + if (opt_background) { + HWND hcon = GetConsoleWindow(); + if (hcon) { + // unhide parent command line windows + ShowWindow(hcon, SW_SHOWMINNOACTIVE); + } + } +#endif + exit(reason); +} + +static inline void work_free(struct work *w) +{ + if (w->txs) free(w->txs); + if (w->workid) free(w->workid); + if (w->job_id) free(w->job_id); + if (w->xnonce2) free(w->xnonce2); } -static bool jobj_binary(const json_t *obj, const char *key, void *buf, - size_t buflen) { - const char *hexstr; - json_t *tmp; - - tmp = json_object_get(obj, key); - if (unlikely(!tmp)) { - applog(LOG_ERR, "JSON key '%s' not found", key); - return false; - } - hexstr = json_string_value(tmp); - if (unlikely(!hexstr)) { - applog(LOG_ERR, "JSON key '%s' is not a string", key); - return false; - } - if (!hex2bin(buf, hexstr, buflen)) - return false; - - return true; +static inline void work_copy(struct work *dest, const struct work *src) +{ + memcpy(dest, src, sizeof(struct work)); + if (src->txs) + dest->txs = strdup(src->txs); + if (src->workid) + dest->workid = strdup(src->workid); + if (src->job_id) + dest->job_id = strdup(src->job_id); + if (src->xnonce2) { + dest->xnonce2 = (uchar*) malloc(src->xnonce2_len); + memcpy(dest->xnonce2, src->xnonce2, src->xnonce2_len); + } } -bool rpc2_job_decode(const json_t *job, struct work *work) { - if (!jsonrpc_2) { - applog(LOG_ERR, "Tried to decode job without JSON-RPC 2.0"); - return false; - } - json_t *tmp; - tmp = json_object_get(job, "job_id"); - if (!tmp) { - applog(LOG_ERR, "JSON inval job id"); - goto err_out; - } - const char *job_id = json_string_value(tmp); - tmp = json_object_get(job, "blob"); - if (!tmp) { - applog(LOG_ERR, "JSON inval blob"); - goto err_out; - } - const char *hexblob = json_string_value(tmp); - int blobLen = strlen(hexblob); - if (blobLen % 2 != 0 || ((blobLen / 2) < 40 && blobLen != 0) || (blobLen / 2) > 128) { - applog(LOG_ERR, "JSON invalid blob length"); - goto err_out; - } - if (blobLen != 0) { - pthread_mutex_lock(&rpc2_job_lock); - char *blob = malloc(blobLen / 2); - if (!hex2bin(blob, hexblob, blobLen / 2)) { - applog(LOG_ERR, "JSON inval blob"); - pthread_mutex_unlock(&rpc2_job_lock); - goto err_out; - } - if (rpc2_blob) { - free(rpc2_blob); - } - rpc2_bloblen = blobLen / 2; - rpc2_blob = malloc(rpc2_bloblen); - memcpy(rpc2_blob, blob, blobLen / 2); - - free(blob); - - uint32_t target; - jobj_binary(job, "target", &target, 4); - if(rpc2_target != target) { - float hashrate = 0.; - pthread_mutex_lock(&stats_lock); - for (size_t i = 0; i < opt_n_threads; i++) - hashrate += thr_hashrates[i]; - pthread_mutex_unlock(&stats_lock); - double difficulty = (((double) 0xffffffff) / target); - applog(LOG_INFO, "Pool set diff to %g", difficulty); - rpc2_target = target; - } - - if (rpc2_job_id) { - free(rpc2_job_id); - } - rpc2_job_id = strdup(job_id); - pthread_mutex_unlock(&rpc2_job_lock); - } - if(work) { - if (!rpc2_blob) { - applog(LOG_ERR, "Requested work before work was received"); - goto err_out; - } - memcpy(work->data, rpc2_blob, rpc2_bloblen); - memset(work->target, 0xff, sizeof(work->target)); - work->target[7] = rpc2_target; - if (work->job_id) - free(work->job_id); - work->job_id = strdup(rpc2_job_id); - } - return true; - - err_out: - return false; +/* compute nbits to get the network diff */ +static void calc_network_diff(struct work *work) +{ + // sample for diff 43.281 : 1c05ea29 + // todo: endian reversed on longpoll could be zr5 specific... + uint32_t nbits = have_longpoll ? work->data[18] : swab32(work->data[18]); + if (opt_algo == ALGO_LBRY) nbits = swab32(work->data[26]); + if (opt_algo == ALGO_DECRED) nbits = work->data[29]; + if (opt_algo == ALGO_SIA) nbits = work->data[11]; // unsure if correct + uint32_t bits = (nbits & 0xffffff); + int16_t shift = (swab32(nbits) & 0xff); // 0x1c = 28 + + double d = (double)0x0000ffff / (double)bits; + for (int m=shift; m < 29; m++) d *= 256.0; + for (int m=29; m < shift; m++) d /= 256.0; + if (opt_algo == ALGO_DECRED && shift == 28) d *= 256.0; // testnet + if (opt_debug_diff) + applog(LOG_DEBUG, "net diff: %f -> shift %u, bits %08x", d, shift, bits); + net_diff = d; } -static bool work_decode(const json_t *val, struct work *work) { - int i; +static bool work_decode(const json_t *val, struct work *work) +{ + int i; + int data_size = 128, target_size = sizeof(work->target); + int adata_sz = 32, atarget_sz = ARRAY_SIZE(work->target); + + if (opt_algo == ALGO_DROP || opt_algo == ALGO_NEOSCRYPT || opt_algo == ALGO_ZR5) { + data_size = 80; target_size = 32; + adata_sz = 20; + atarget_sz = target_size / sizeof(uint32_t); + } else if (opt_algo == ALGO_DECRED) { + allow_mininginfo = false; + data_size = 192; + adata_sz = 180/4; + } else if (use_roots) { + data_size = 144; + adata_sz = 36; + } + + if (jsonrpc_2) { + return rpc2_job_decode(val, work); + } + + if (unlikely(!jobj_binary(val, "data", work->data, data_size))) { + applog(LOG_ERR, "JSON invalid data"); + goto err_out; + } + if (unlikely(!jobj_binary(val, "target", work->target, target_size))) { + applog(LOG_ERR, "JSON invalid target"); + goto err_out; + } + + for (i = 0; i < adata_sz; i++) + work->data[i] = le32dec(work->data + i); + for (i = 0; i < atarget_sz; i++) + work->target[i] = le32dec(work->target + i); - if(jsonrpc_2) { - return rpc2_job_decode(val, work); - } + if ((opt_showdiff || opt_max_diff > 0.) && !allow_mininginfo) + calc_network_diff(work); - if (unlikely(!jobj_binary(val, "data", work->data, sizeof(work->data)))) { - applog(LOG_ERR, "JSON inval data"); - goto err_out; - } - if (unlikely(!jobj_binary(val, "target", work->target, sizeof(work->target)))) { - applog(LOG_ERR, "JSON inval target"); - goto err_out; - } + work->targetdiff = target_to_diff(work->target); - for (i = 0; i < ARRAY_SIZE(work->data); i++) - work->data[i] = le32dec(work->data + i); - for (i = 0; i < ARRAY_SIZE(work->target); i++) - work->target[i] = le32dec(work->target + i); + // for api stats, on longpoll pools + stratum_diff = work->targetdiff; - return true; + if (opt_algo == ALGO_DROP || opt_algo == ALGO_ZR5) { + #define POK_BOOL_MASK 0x00008000 + #define POK_DATA_MASK 0xFFFF0000 + if (work->data[0] & POK_BOOL_MASK) { + applog(LOG_BLUE, "POK received: %08xx", work->data[0]); + zr5_pok = work->data[0] & POK_DATA_MASK; + } + } else if (opt_algo == ALGO_DECRED) { + // some random extradata to make the work unique + work->data[36] = (rand()*4); + work->height = work->data[32]; + // required for the getwork pools (multicoin.co) + if (!have_longpoll && work->height > net_blocks + 1) { + char netinfo[64] = { 0 }; + if (opt_showdiff && net_diff > 0.) { + if (net_diff != work->targetdiff) + sprintf(netinfo, ", diff %.3f, target %.1f", net_diff, work->targetdiff); + else + sprintf(netinfo, ", diff %.3f", net_diff); + } + applog(LOG_BLUE, "%s block %d%s", + algo_names[opt_algo], work->height, netinfo); + net_blocks = work->height - 1; + } + } else if (opt_algo == ALGO_PHI2) { + if (work->data[0] & (1<<30)) use_roots = true; + else for (i = 20; i < 36; i++) { + if (work->data[i]) { use_roots = true; break; } + } + } - err_out: return false; + return true; + +err_out: + return false; } -bool rpc2_login_decode(const json_t *val) { - const char *id; - const char *s; - - json_t *res = json_object_get(val, "result"); - if(!res) { - applog(LOG_ERR, "JSON invalid result"); - goto err_out; - } - - json_t *tmp; - tmp = json_object_get(res, "id"); - if(!tmp) { - applog(LOG_ERR, "JSON inval id"); - goto err_out; - } - id = json_string_value(tmp); - if(!id) { - applog(LOG_ERR, "JSON id is not a string"); - goto err_out; - } - - memcpy(&rpc2_id, id, 64); - - if(opt_debug) - applog(LOG_DEBUG, "Auth id: %s", id); - - tmp = json_object_get(res, "status"); - if(!tmp) { - applog(LOG_ERR, "JSON inval status"); - goto err_out; - } - s = json_string_value(tmp); - if(!s) { - applog(LOG_ERR, "JSON status is not a string"); - goto err_out; - } - if(strcmp(s, "OK")) { - applog(LOG_ERR, "JSON returned status \"%s\"", s); - return false; - } - - return true; - - err_out: return false; +// good alternative for wallet mining, difficulty and net hashrate +static const char *info_req = +"{\"method\": \"getmininginfo\", \"params\": [], \"id\":8}\r\n"; + +static bool get_mininginfo(CURL *curl, struct work *work) +{ + if (have_stratum || have_longpoll || !allow_mininginfo) + return false; + + int curl_err = 0; + json_t *val = json_rpc_call(curl, rpc_url, rpc_userpass, info_req, &curl_err, 0); + + if (!val && curl_err == -1) { + allow_mininginfo = false; + if (opt_debug) { + applog(LOG_DEBUG, "getmininginfo not supported"); + } + return false; + } + else { + json_t *res = json_object_get(val, "result"); + // "blocks": 491493 (= current work height - 1) + // "difficulty": 0.99607860999999998 + // "networkhashps": 56475980 + if (res) { + json_t *key = json_object_get(res, "difficulty"); + if (key) { + if (json_is_object(key)) + key = json_object_get(key, "proof-of-work"); + if (json_is_real(key)) + net_diff = json_real_value(key); + } + key = json_object_get(res, "networkhashps"); + if (key && json_is_integer(key)) { + net_hashrate = (double) json_integer_value(key); + } + key = json_object_get(res, "blocks"); + if (key && json_is_integer(key)) { + net_blocks = json_integer_value(key); + } + if (!work->height) { + // complete missing data from getwork + work->height = (uint32_t) net_blocks + 1; + if (work->height > g_work.height) { + restart_threads(); + if (!opt_quiet) { + char netinfo[64] = { 0 }; + char srate[32] = { 0 }; + sprintf(netinfo, "diff %.2f", net_diff); + if (net_hashrate) { + format_hashrate(net_hashrate, srate); + strcat(netinfo, ", net "); + strcat(netinfo, srate); + } + applog(LOG_BLUE, "%s block %d, %s", + algo_names[opt_algo], work->height, netinfo); + } + } + } + } + } + json_decref(val); + return true; } -static void share_result(int result, struct work *work, const char *reason) { - char s[345]; - double hashrate; - int i; - - hashrate = 0.; - pthread_mutex_lock(&stats_lock); - for (i = 0; i < opt_n_threads; i++) - hashrate += thr_hashrates[i]; - result ? accepted_count++ : rejected_count++; - pthread_mutex_unlock(&stats_lock); - - switch (opt_algo) { - case ALGO_CRYPTONIGHT: - applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %.2f H/s at diff %g %s", - accepted_count, accepted_count + rejected_count, - 100. * accepted_count / (accepted_count + rejected_count), hashrate, - (((double) 0xffffffff) / (work ? work->target[7] : rpc2_target)), - result ? "(yay!!!)" : "(booooo)"); - break; - default: - sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", 1e-3 * hashrate); - applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %s khash/s %s", - accepted_count, accepted_count + rejected_count, - 100. * accepted_count / (accepted_count + rejected_count), s, - result ? "(yay!!!)" : "(booooo)"); - break; - } - - if (opt_debug && reason) - applog(LOG_DEBUG, "DEBUG: reject reason: %s", reason); +#define BLOCK_VERSION_CURRENT 3 + +static bool gbt_work_decode(const json_t *val, struct work *work) +{ + int i, n; + uint32_t version, curtime, bits; + uint32_t prevhash[8]; + uint32_t target[8]; + int cbtx_size; + uchar *cbtx = NULL; + int tx_count, tx_size; + uchar txc_vi[9]; + uchar(*merkle_tree)[32] = NULL; + bool coinbase_append = false; + bool submit_coinbase = false; + bool version_force = false; + bool version_reduce = false; + json_t *tmp, *txa; + bool rc = false; + + tmp = json_object_get(val, "mutable"); + if (tmp && json_is_array(tmp)) { + n = (int) json_array_size(tmp); + for (i = 0; i < n; i++) { + const char *s = json_string_value(json_array_get(tmp, i)); + if (!s) + continue; + if (!strcmp(s, "coinbase/append")) + coinbase_append = true; + else if (!strcmp(s, "submit/coinbase")) + submit_coinbase = true; + else if (!strcmp(s, "version/force")) + version_force = true; + else if (!strcmp(s, "version/reduce")) + version_reduce = true; + } + } + + tmp = json_object_get(val, "height"); + if (!tmp || !json_is_integer(tmp)) { + applog(LOG_ERR, "JSON invalid height"); + goto out; + } + work->height = (int) json_integer_value(tmp); + applog(LOG_BLUE, "Current block is %d", work->height); + + tmp = json_object_get(val, "version"); + if (!tmp || !json_is_integer(tmp)) { + applog(LOG_ERR, "JSON invalid version"); + goto out; + } + version = (uint32_t) json_integer_value(tmp); + if ((version & 0xffU) > BLOCK_VERSION_CURRENT) { + if (version_reduce) { + version = (version & ~0xffU) | BLOCK_VERSION_CURRENT; + } else if (have_gbt && allow_getwork && !version_force) { + applog(LOG_DEBUG, "Switching to getwork, gbt version %d", version); + have_gbt = false; + goto out; + } else if (!version_force) { + applog(LOG_ERR, "Unrecognized block version: %u", version); + goto out; + } + } + + if (unlikely(!jobj_binary(val, "previousblockhash", prevhash, sizeof(prevhash)))) { + applog(LOG_ERR, "JSON invalid previousblockhash"); + goto out; + } + + tmp = json_object_get(val, "curtime"); + if (!tmp || !json_is_integer(tmp)) { + applog(LOG_ERR, "JSON invalid curtime"); + goto out; + } + curtime = (uint32_t) json_integer_value(tmp); + + if (unlikely(!jobj_binary(val, "bits", &bits, sizeof(bits)))) { + applog(LOG_ERR, "JSON invalid bits"); + goto out; + } + + /* find count and size of transactions */ + txa = json_object_get(val, "transactions"); + if (!txa || !json_is_array(txa)) { + applog(LOG_ERR, "JSON invalid transactions"); + goto out; + } + tx_count = (int) json_array_size(txa); + tx_size = 0; + for (i = 0; i < tx_count; i++) { + const json_t *tx = json_array_get(txa, i); + const char *tx_hex = json_string_value(json_object_get(tx, "data")); + if (!tx_hex) { + applog(LOG_ERR, "JSON invalid transactions"); + goto out; + } + tx_size += (int) (strlen(tx_hex) / 2); + } + + /* build coinbase transaction */ + tmp = json_object_get(val, "coinbasetxn"); + if (tmp) { + const char *cbtx_hex = json_string_value(json_object_get(tmp, "data")); + cbtx_size = cbtx_hex ? (int) strlen(cbtx_hex) / 2 : 0; + cbtx = (uchar*) malloc(cbtx_size + 100); + if (cbtx_size < 60 || !hex2bin(cbtx, cbtx_hex, cbtx_size)) { + applog(LOG_ERR, "JSON invalid coinbasetxn"); + goto out; + } + } else { + int64_t cbvalue; + if (!pk_script_size) { + if (allow_getwork) { + applog(LOG_INFO, "No payout address provided, switching to getwork"); + have_gbt = false; + } else + applog(LOG_ERR, "No payout address provided"); + goto out; + } + tmp = json_object_get(val, "coinbasevalue"); + if (!tmp || !json_is_number(tmp)) { + applog(LOG_ERR, "JSON invalid coinbasevalue"); + goto out; + } + cbvalue = (int64_t) (json_is_integer(tmp) ? json_integer_value(tmp) : json_number_value(tmp)); + cbtx = (uchar*) malloc(256); + le32enc((uint32_t *)cbtx, 1); /* version */ + cbtx[4] = 1; /* in-counter */ + memset(cbtx+5, 0x00, 32); /* prev txout hash */ + le32enc((uint32_t *)(cbtx+37), 0xffffffff); /* prev txout index */ + cbtx_size = 43; + /* BIP 34: height in coinbase */ + for (n = work->height; n; n >>= 8) + cbtx[cbtx_size++] = n & 0xff; + /* If the last byte pushed is >= 0x80, then we need to add + another zero byte to signal that the block height is a + positive number. */ + if (cbtx[cbtx_size - 1] & 0x80) + cbtx[cbtx_size++] = 0; + cbtx[42] = cbtx_size - 43; + cbtx[41] = cbtx_size - 42; /* scriptsig length */ + le32enc((uint32_t *)(cbtx+cbtx_size), 0xffffffff); /* sequence */ + cbtx_size += 4; + cbtx[cbtx_size++] = 1; /* out-counter */ + le32enc((uint32_t *)(cbtx+cbtx_size), (uint32_t)cbvalue); /* value */ + le32enc((uint32_t *)(cbtx+cbtx_size+4), cbvalue >> 32); + cbtx_size += 8; + cbtx[cbtx_size++] = (uint8_t) pk_script_size; /* txout-script length */ + memcpy(cbtx+cbtx_size, pk_script, pk_script_size); + cbtx_size += (int) pk_script_size; + le32enc((uint32_t *)(cbtx+cbtx_size), 0); /* lock time */ + cbtx_size += 4; + coinbase_append = true; + } + if (coinbase_append) { + unsigned char xsig[100]; + int xsig_len = 0; + if (*coinbase_sig) { + n = (int) strlen(coinbase_sig); + if (cbtx[41] + xsig_len + n <= 100) { + memcpy(xsig+xsig_len, coinbase_sig, n); + xsig_len += n; + } else { + applog(LOG_WARNING, "Signature does not fit in coinbase, skipping"); + } + } + tmp = json_object_get(val, "coinbaseaux"); + if (tmp && json_is_object(tmp)) { + void *iter = json_object_iter(tmp); + while (iter) { + unsigned char buf[100]; + const char *s = json_string_value(json_object_iter_value(iter)); + n = s ? (int) (strlen(s) / 2) : 0; + if (!s || n > 100 || !hex2bin(buf, s, n)) { + applog(LOG_ERR, "JSON invalid coinbaseaux"); + break; + } + if (cbtx[41] + xsig_len + n <= 100) { + memcpy(xsig+xsig_len, buf, n); + xsig_len += n; + } + iter = json_object_iter_next(tmp, iter); + } + } + if (xsig_len) { + unsigned char *ssig_end = cbtx + 42 + cbtx[41]; + int push_len = cbtx[41] + xsig_len < 76 ? 1 : + cbtx[41] + 2 + xsig_len > 100 ? 0 : 2; + n = xsig_len + push_len; + memmove(ssig_end + n, ssig_end, cbtx_size - 42 - cbtx[41]); + cbtx[41] += n; + if (push_len == 2) + *(ssig_end++) = 0x4c; /* OP_PUSHDATA1 */ + if (push_len) + *(ssig_end++) = xsig_len; + memcpy(ssig_end, xsig, xsig_len); + cbtx_size += n; + } + } + + n = varint_encode(txc_vi, 1 + tx_count); + work->txs = (char*) malloc(2 * (n + cbtx_size + tx_size) + 1); + bin2hex(work->txs, txc_vi, n); + bin2hex(work->txs + 2*n, cbtx, cbtx_size); + + /* generate merkle root */ + merkle_tree = (uchar(*)[32]) calloc(((1 + tx_count + 1) & ~1), 32); + sha256d(merkle_tree[0], cbtx, cbtx_size); + for (i = 0; i < tx_count; i++) { + tmp = json_array_get(txa, i); + const char *tx_hex = json_string_value(json_object_get(tmp, "data")); + const int tx_size = tx_hex ? (int) (strlen(tx_hex) / 2) : 0; + unsigned char *tx = (uchar*) malloc(tx_size); + if (!tx_hex || !hex2bin(tx, tx_hex, tx_size)) { + applog(LOG_ERR, "JSON invalid transactions"); + free(tx); + goto out; + } + sha256d(merkle_tree[1 + i], tx, tx_size); + if (!submit_coinbase) + strcat(work->txs, tx_hex); + } + n = 1 + tx_count; + while (n > 1) { + if (n % 2) { + memcpy(merkle_tree[n], merkle_tree[n-1], 32); + ++n; + } + n /= 2; + for (i = 0; i < n; i++) + sha256d(merkle_tree[i], merkle_tree[2*i], 64); + } + + /* assemble block header */ + work->data[0] = swab32(version); + for (i = 0; i < 8; i++) + work->data[8 - i] = le32dec(prevhash + i); + for (i = 0; i < 8; i++) + work->data[9 + i] = be32dec((uint32_t *)merkle_tree[0] + i); + work->data[17] = swab32(curtime); + work->data[18] = le32dec(&bits); + memset(work->data + 19, 0x00, 52); + + work->data[20] = 0x80000000; + work->data[31] = 0x00000280; + + if (unlikely(!jobj_binary(val, "target", target, sizeof(target)))) { + applog(LOG_ERR, "JSON invalid target"); + goto out; + } + for (i = 0; i < ARRAY_SIZE(work->target); i++) + work->target[7 - i] = be32dec(target + i); + + tmp = json_object_get(val, "workid"); + if (tmp) { + if (!json_is_string(tmp)) { + applog(LOG_ERR, "JSON invalid workid"); + goto out; + } + work->workid = strdup(json_string_value(tmp)); + } + + rc = true; +out: + /* Long polling */ + tmp = json_object_get(val, "longpollid"); + if (want_longpoll && json_is_string(tmp)) { + free(lp_id); + lp_id = strdup(json_string_value(tmp)); + if (!have_longpoll) { + char *lp_uri; + tmp = json_object_get(val, "longpolluri"); + lp_uri = json_is_string(tmp) ? strdup(json_string_value(tmp)) : rpc_url; + have_longpoll = true; + tq_push(thr_info[longpoll_thr_id].q, lp_uri); + } + } + + free(merkle_tree); + free(cbtx); + return rc; } -static bool submit_upstream_work(CURL *curl, struct work *work) { - char *str = NULL; - json_t *val, *res, *reason; - char s[JSON_BUF_LEN]; - int i; - bool rc = false; - - /* pass if the previous hash is not the current previous hash */ - if (!submit_old && memcmp(work->data + 1, g_work.data + 1, 32)) { - if (opt_debug) - applog(LOG_DEBUG, "DEBUG: stale work detected, discarding"); - return true; - } - - if (have_stratum) { - uint32_t ntime, nonce; - char *ntimestr, *noncestr, *xnonce2str; - - if (jsonrpc_2) { - noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4); - char hash[32]; - switch(opt_algo) { - case ALGO_CRYPTONIGHT: - default: - cryptonight_hash(hash, work->data, 76); - } - char *hashhex = bin2hex(hash, 32); - snprintf(s, JSON_BUF_LEN, - "{\"method\": \"submit\", \"params\": {\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}, \"id\":1}\r\n", - rpc2_id, work->job_id, noncestr, hashhex); - free(hashhex); - } else { - le32enc(&ntime, work->data[17]); - le32enc(&nonce, work->data[19]); - ntimestr = bin2hex((const unsigned char *) (&ntime), 4); - noncestr = bin2hex((const unsigned char *) (&nonce), 4); - xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len); - snprintf(s, JSON_BUF_LEN, - "{\"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":4}", - rpc_user, work->job_id, xnonce2str, ntimestr, noncestr); - free(ntimestr); - free(xnonce2str); - } - free(noncestr); - - if (unlikely(!stratum_send_line(&stratum, s))) { - applog(LOG_ERR, "submit_upstream_work stratum_send_line failed"); - goto out; - } - } else { - /* build JSON-RPC request */ - if(jsonrpc_2) { - char *noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4); - char hash[32]; - switch(opt_algo) { - case ALGO_CRYPTONIGHT: - default: - cryptonight_hash(hash, work->data, 76); - } - char *hashhex = bin2hex(hash, 32); - snprintf(s, JSON_BUF_LEN, - "{\"method\": \"submit\", \"params\": {\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}, \"id\":1}\r\n", - rpc2_id, work->job_id, noncestr, hashhex); - free(noncestr); - free(hashhex); - - /* issue JSON-RPC request */ - val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0); - if (unlikely(!val)) { - applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); - goto out; - } - res = json_object_get(val, "result"); - json_t *status = json_object_get(res, "status"); - reason = json_object_get(res, "reject-reason"); - share_result(!strcmp(status ? json_string_value(status) : "", "OK"), work, - reason ? json_string_value(reason) : NULL ); - } else { - /* build hex string */ - for (i = 0; i < 76; i++) - le32enc(((char*)work->data) + i, *((uint32_t*) (((char*)work->data) + i))); - str = bin2hex((unsigned char *) work->data, 76); - if (unlikely(!str)) { - applog(LOG_ERR, "submit_upstream_work OOM"); - goto out; - } - snprintf(s, JSON_BUF_LEN, - "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", - str); - - /* issue JSON-RPC request */ - val = json_rpc_call(curl, rpc_url, rpc_userpass, s, NULL, 0); - if (unlikely(!val)) { - applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); - goto out; - } - res = json_object_get(val, "result"); - reason = json_object_get(val, "reject-reason"); - share_result(json_is_true(res), work, - reason ? json_string_value(reason) : NULL ); - } - - json_decref(val); - } - - rc = true; - - out: free(str); - return rc; +#define YES "yes!" +#define YAY "yay!!!" +#define BOO "booooo" + +static int share_result(int result, struct work *work, const char *reason) +{ + const char *flag; + char suppl[32] = { 0 }; + char s[345]; + double hashrate; + double sharediff = work ? work->sharediff : stratum.sharediff; + int i; + + hashrate = 0.; + pthread_mutex_lock(&stats_lock); + for (i = 0; i < opt_n_threads; i++) + hashrate += thr_hashrates[i]; + result ? accepted_count++ : rejected_count++; + pthread_mutex_unlock(&stats_lock); + + global_hashrate = (uint64_t) hashrate; + + if (!net_diff || sharediff < net_diff) { + flag = use_colors ? + (result ? CL_GRN YES : CL_RED BOO) + : (result ? "(" YES ")" : "(" BOO ")"); + } else { + solved_count++; + flag = use_colors ? + (result ? CL_GRN YAY : CL_RED BOO) + : (result ? "(" YAY ")" : "(" BOO ")"); + } + + if (opt_showdiff) + sprintf(suppl, "diff %.3f", sharediff); + else // accepted percent + sprintf(suppl, "%.2f%%", 100. * accepted_count / (accepted_count + rejected_count)); + + switch (opt_algo) { + case ALGO_AXIOM: + case ALGO_CRYPTOLIGHT: + case ALGO_CRYPTONIGHT: + case ALGO_PLUCK: + case ALGO_SCRYPTJANE: + sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate); + applog(LOG_NOTICE, "accepted: %lu/%lu (%s), %s H/s %s", + accepted_count, accepted_count + rejected_count, + suppl, s, flag); + break; + default: + sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000.0); + applog(LOG_NOTICE, "accepted: %lu/%lu (%s), %s kH/s %s", + accepted_count, accepted_count + rejected_count, + suppl, s, flag); + break; + } + + if (reason) { + applog(LOG_WARNING, "reject reason: %s", reason); + if (0 && strncmp(reason, "low difficulty share", 20) == 0) { + opt_diff_factor = (opt_diff_factor * 2.0) / 3.0; + applog(LOG_WARNING, "factor reduced to : %0.2f", opt_diff_factor); + return 0; + } + } + return 1; } -static const char *rpc_req = - "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; +static bool submit_upstream_work(CURL *curl, struct work *work) +{ + json_t *val, *res, *reason; + char s[JSON_BUF_LEN]; + int i; + bool rc = false; -static bool get_upstream_work(CURL *curl, struct work *work) { - json_t *val; - bool rc; - struct timeval tv_start, tv_end, diff; + /* pass if the previous hash is not the current previous hash */ + if (opt_algo != ALGO_SIA && !submit_old && memcmp(&work->data[1], &g_work.data[1], 32)) { + if (opt_debug) + applog(LOG_DEBUG, "DEBUG: stale work detected, discarding"); + return true; + } - gettimeofday(&tv_start, NULL ); + if (!have_stratum && allow_mininginfo) { + struct work wheight; + get_mininginfo(curl, &wheight); + if (work->height && work->height <= net_blocks) { + if (opt_debug) + applog(LOG_WARNING, "block %u was already solved", work->height); + return true; + } + } - if(jsonrpc_2) { - char s[128]; - snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id); - val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0); - } else { - val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req, NULL, 0); - } - gettimeofday(&tv_end, NULL ); + if (have_stratum) { + uint32_t ntime, nonce; + char ntimestr[9], noncestr[9]; + + if (jsonrpc_2) { + uchar hash[32]; + + bin2hex(noncestr, (const unsigned char *)work->data + 39, 4); + switch(opt_algo) { + case ALGO_CRYPTOLIGHT: + cryptolight_hash(hash, work->data); + break; + case ALGO_CRYPTONIGHT: + cryptonight_hash(hash, work->data); + default: + break; + } + char *hashhex = abin2hex(hash, 32); + snprintf(s, JSON_BUF_LEN, + "{\"method\": \"submit\", \"params\": {\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}, \"id\":4}\r\n", + rpc2_id, work->job_id, noncestr, hashhex); + free(hashhex); + } else { + char *xnonce2str; + + switch (opt_algo) { + case ALGO_DECRED: + /* reversed */ + be32enc(&ntime, work->data[34]); + be32enc(&nonce, work->data[35]); + break; + case ALGO_LBRY: + le32enc(&ntime, work->data[25]); + le32enc(&nonce, work->data[27]); + break; + case ALGO_DROP: + case ALGO_NEOSCRYPT: + case ALGO_ZR5: + /* reversed */ + be32enc(&ntime, work->data[17]); + be32enc(&nonce, work->data[19]); + break; + case ALGO_SIA: + /* reversed */ + be32enc(&ntime, work->data[10]); + be32enc(&nonce, work->data[8]); + break; + default: + le32enc(&ntime, work->data[17]); + le32enc(&nonce, work->data[19]); + } + + bin2hex(ntimestr, (const unsigned char *)(&ntime), 4); + bin2hex(noncestr, (const unsigned char *)(&nonce), 4); + if (opt_algo == ALGO_DECRED) { + xnonce2str = abin2hex((unsigned char*)(&work->data[36]), stratum.xnonce1_size); + } else if (opt_algo == ALGO_SIA) { + uint16_t high_nonce = swab32(work->data[9]) >> 16; + xnonce2str = abin2hex((unsigned char*)(&high_nonce), 2); + } else { + xnonce2str = abin2hex(work->xnonce2, work->xnonce2_len); + } + snprintf(s, JSON_BUF_LEN, + "{\"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":4}", + rpc_user, work->job_id, xnonce2str, ntimestr, noncestr); + free(xnonce2str); + } - if (have_stratum) { - if (val) - json_decref(val); - return true; - } + // store to keep/display solved blocs (work struct not linked on accept notification) + stratum.sharediff = work->sharediff; - if (!val) - return false; + if (unlikely(!stratum_send_line(&stratum, s))) { + applog(LOG_ERR, "submit_upstream_work stratum_send_line failed"); + goto out; + } + + } else if (work->txs) { /* gbt */ + + char data_str[2 * sizeof(work->data) + 1]; + char *req; + + for (i = 0; i < ARRAY_SIZE(work->data); i++) + be32enc(work->data + i, work->data[i]); + bin2hex(data_str, (unsigned char *)work->data, 80); + if (work->workid) { + char *params; + val = json_object(); + json_object_set_new(val, "workid", json_string(work->workid)); + params = json_dumps(val, 0); + json_decref(val); + req = (char*) malloc(128 + 2 * 80 + strlen(work->txs) + strlen(params)); + sprintf(req, + "{\"method\": \"submitblock\", \"params\": [\"%s%s\", %s], \"id\":4}\r\n", + data_str, work->txs, params); + free(params); + } else { + req = (char*) malloc(128 + 2 * 80 + strlen(work->txs)); + sprintf(req, + "{\"method\": \"submitblock\", \"params\": [\"%s%s\"], \"id\":4}\r\n", + data_str, work->txs); + } - rc = work_decode(json_object_get(val, "result"), work); + val = json_rpc_call(curl, rpc_url, rpc_userpass, req, NULL, 0); + free(req); + if (unlikely(!val)) { + applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); + goto out; + } - if (opt_debug && rc) { - timeval_subtract(&diff, &tv_end, &tv_start); - applog(LOG_DEBUG, "DEBUG: got new work in %d ms", - diff.tv_sec * 1000 + diff.tv_usec / 1000); - } + res = json_object_get(val, "result"); + if (json_is_object(res)) { + char *res_str; + bool sumres = false; + void *iter = json_object_iter(res); + while (iter) { + if (json_is_null(json_object_iter_value(iter))) { + sumres = true; + break; + } + iter = json_object_iter_next(res, iter); + } + res_str = json_dumps(res, 0); + share_result(sumres, work, res_str); + free(res_str); + } else + share_result(json_is_null(res), work, json_string_value(res)); + + json_decref(val); - json_decref(val); + } else { + + char* gw_str = NULL; + int data_size = 128; + int adata_sz; + + if (jsonrpc_2) { + char noncestr[9]; + uchar hash[32]; + char *hashhex; + + bin2hex(noncestr, (const unsigned char *)work->data + 39, 4); + + switch(opt_algo) { + case ALGO_CRYPTOLIGHT: + cryptolight_hash(hash, work->data); + break; + case ALGO_CRYPTONIGHT: + cryptonight_hash(hash, work->data); + default: + break; + } + hashhex = abin2hex(&hash[0], 32); + snprintf(s, JSON_BUF_LEN, + "{\"method\": \"submit\", \"params\": " + "{\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}," + "\"id\":4}\r\n", + rpc2_id, work->job_id, noncestr, hashhex); + free(hashhex); + + /* issue JSON-RPC request */ + val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0); + if (unlikely(!val)) { + applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); + goto out; + } + res = json_object_get(val, "result"); + json_t *status = json_object_get(res, "status"); + bool valid = !strcmp(status ? json_string_value(status) : "", "OK"); + if (valid) + share_result(valid, work, NULL); + else { + json_t *err = json_object_get(res, "error"); + const char *sreason = json_string_value(json_object_get(err, "message")); + share_result(valid, work, sreason); + if (!strcasecmp("Invalid job id", sreason)) { + work_free(work); + work_copy(work, &g_work); + g_work_time = 0; + restart_threads(); + } + } + json_decref(val); + return true; + + } else if (opt_algo == ALGO_DROP || opt_algo == ALGO_NEOSCRYPT || opt_algo == ALGO_ZR5) { + /* different data size */ + data_size = 80; + } else if (opt_algo == ALGO_DECRED) { + /* bigger data size : 180 + terminal hash ending */ + data_size = 192; + } else if (opt_algo == ALGO_PHI2 && use_roots) { + data_size = 144; + } - return rc; + adata_sz = data_size / sizeof(uint32_t); + if (opt_algo == ALGO_DECRED) adata_sz = 180 / 4; // dont touch the end tag + + /* build hex string */ + for (i = 0; i < adata_sz; i++) + le32enc(&work->data[i], work->data[i]); + + gw_str = abin2hex((uchar*)work->data, data_size); + + if (unlikely(!gw_str)) { + applog(LOG_ERR, "submit_upstream_work OOM"); + return false; + } + + //applog(LOG_WARNING, gw_str); + + /* build JSON-RPC request */ + snprintf(s, JSON_BUF_LEN, + "{\"method\": \"getwork\", \"params\": [\"%s\"], \"id\":4}\r\n", gw_str); + free(gw_str); + + /* issue JSON-RPC request */ + val = json_rpc_call(curl, rpc_url, rpc_userpass, s, NULL, 0); + if (unlikely(!val)) { + applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); + goto out; + } + res = json_object_get(val, "result"); + reason = json_object_get(val, "reject-reason"); + share_result(json_is_true(res), work, reason ? json_string_value(reason) : NULL); + + json_decref(val); + } + + rc = true; + +out: + return rc; } -static bool rpc2_login(CURL *curl) { - if(!jsonrpc_2) { - return false; - } - json_t *val; - bool rc; - struct timeval tv_start, tv_end, diff; - char s[JSON_BUF_LEN]; +static const char *getwork_req = + "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; - snprintf(s, JSON_BUF_LEN, "{\"method\": \"login\", \"params\": {\"login\": \"%s\", \"pass\": \"%s\", \"agent\": \"cpuminer-multi/0.1\"}, \"id\": 1}", rpc_user, rpc_pass); +#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]" - gettimeofday(&tv_start, NULL ); - val = json_rpc_call(curl, rpc_url, rpc_userpass, s, NULL, 0); - gettimeofday(&tv_end, NULL ); +static const char *gbt_req = + "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": " + GBT_CAPABILITIES "}], \"id\":0}\r\n"; +static const char *gbt_lp_req = + "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": " + GBT_CAPABILITIES ", \"longpollid\": \"%s\"}], \"id\":0}\r\n"; - if (!val) - goto end; +static bool get_upstream_work(CURL *curl, struct work *work) +{ + json_t *val; + int err; + bool rc; + struct timeval tv_start, tv_end, diff; + +start: + gettimeofday(&tv_start, NULL); + + if (jsonrpc_2) { + char s[128]; + snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id); + val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0); + } else { + val = json_rpc_call(curl, rpc_url, rpc_userpass, + have_gbt ? gbt_req : getwork_req, + &err, have_gbt ? JSON_RPC_QUIET_404 : 0); + } + gettimeofday(&tv_end, NULL); -// applog(LOG_DEBUG, "JSON value: %s", json_dumps(val, 0)); + if (have_stratum) { + if (val) + json_decref(val); + return true; + } - rc = rpc2_login_decode(val); + if (!have_gbt && !allow_getwork) { + applog(LOG_ERR, "No usable protocol"); + if (val) + json_decref(val); + return false; + } - json_t *result = json_object_get(val, "result"); + if (have_gbt && allow_getwork && !val && err == CURLE_OK) { + applog(LOG_NOTICE, "getblocktemplate failed, falling back to getwork"); + have_gbt = false; + goto start; + } - if(!result) goto end; + if (!val) + return false; - json_t *job = json_object_get(result, "job"); + if (have_gbt) { + rc = gbt_work_decode(json_object_get(val, "result"), work); + if (!have_gbt) { + json_decref(val); + goto start; + } + } else { + rc = work_decode(json_object_get(val, "result"), work); + } - if(!rpc2_job_decode(job, &g_work)) { - goto end; - } + if (opt_protocol && rc) { + timeval_subtract(&diff, &tv_end, &tv_start); + applog(LOG_DEBUG, "got new work in %.2f ms", + (1000.0 * diff.tv_sec) + (0.001 * diff.tv_usec)); + } - if (opt_debug && rc) { - timeval_subtract(&diff, &tv_end, &tv_start); - applog(LOG_DEBUG, "DEBUG: authenticated in %d ms", - diff.tv_sec * 1000 + diff.tv_usec / 1000); - } + json_decref(val); - json_decref(val); + // store work height in solo + get_mininginfo(curl, work); - end: - return rc; + return rc; } -static void workio_cmd_free(struct workio_cmd *wc) { - if (!wc) - return; - - switch (wc->cmd) { - case WC_SUBMIT_WORK: - work_free(wc->u.work); - free(wc->u.work); - break; - default: /* do nothing */ - break; - } - - memset(wc, 0, sizeof(*wc)); /* poison */ - free(wc); +static void workio_cmd_free(struct workio_cmd *wc) +{ + if (!wc) + return; + + switch (wc->cmd) { + case WC_SUBMIT_WORK: + work_free(wc->u.work); + free(wc->u.work); + break; + default: /* do nothing */ + break; + } + + memset(wc, 0, sizeof(*wc)); /* poison */ + free(wc); +} + +static bool workio_get_work(struct workio_cmd *wc, CURL *curl) +{ + struct work *ret_work; + int failures = 0; + + ret_work = (struct work*) calloc(1, sizeof(*ret_work)); + if (!ret_work) + return false; + + /* obtain new work from bitcoin via JSON-RPC */ + while (!get_upstream_work(curl, ret_work)) { + if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { + applog(LOG_ERR, "json_rpc_call failed, terminating workio thread"); + free(ret_work); + return false; + } + + /* pause, then restart work-request loop */ + applog(LOG_ERR, "json_rpc_call failed, retry after %d seconds", + opt_fail_pause); + sleep(opt_fail_pause); + } + + /* send work to requesting thread */ + if (!tq_push(wc->thr->q, ret_work)) + free(ret_work); + + return true; } -static bool workio_get_work(struct workio_cmd *wc, CURL *curl) { - struct work *ret_work; - int failures = 0; - - ret_work = calloc(1, sizeof(*ret_work)); - if (!ret_work) - return false; - - /* obtain new work from bitcoin via JSON-RPC */ - while (!get_upstream_work(curl, ret_work)) { - if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { - applog(LOG_ERR, "json_rpc_call failed, terminating workio thread"); - free(ret_work); - return false; - } - - /* pause, then restart work-request loop */ - applog(LOG_ERR, "getwork failed, retry after %d seconds", - opt_fail_pause); - sleep(opt_fail_pause); - } - - /* send work to requesting thread */ - if (!tq_push(wc->thr->q, ret_work)) - free(ret_work); - - return true; +static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) +{ + int failures = 0; + + /* submit solution to bitcoin via JSON-RPC */ + while (!submit_upstream_work(curl, wc->u.work)) { + if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { + applog(LOG_ERR, "...terminating workio thread"); + return false; + } + + /* pause, then restart work-request loop */ + if (!opt_benchmark) + applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause); + sleep(opt_fail_pause); + } + + return true; } -static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) { - int failures = 0; +bool rpc2_login(CURL *curl) +{ + json_t *val; + bool rc = false; + struct timeval tv_start, tv_end, diff; + char s[JSON_BUF_LEN]; + + if (!jsonrpc_2) + return false; + + snprintf(s, JSON_BUF_LEN, "{\"method\": \"login\", \"params\": {" + "\"login\": \"%s\", \"pass\": \"%s\", \"agent\": \"%s\"}, \"id\": 1}", + rpc_user, rpc_pass, USER_AGENT); + + gettimeofday(&tv_start, NULL); + val = json_rpc_call(curl, rpc_url, rpc_userpass, s, NULL, 0); + gettimeofday(&tv_end, NULL); - /* submit solution to bitcoin via JSON-RPC */ - while (!submit_upstream_work(curl, wc->u.work)) { - if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { - applog(LOG_ERR, "...terminating workio thread"); - return false; - } + if (!val) + goto end; - /* pause, then restart work-request loop */ - applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause); - sleep(opt_fail_pause); - } +// applog(LOG_DEBUG, "JSON value: %s", json_dumps(val, 0)); - return true; + rc = rpc2_login_decode(val); + + json_t *result = json_object_get(val, "result"); + + if (!result) + goto end; + + json_t *job = json_object_get(result, "job"); + if (!rpc2_job_decode(job, &g_work)) { + goto end; + } + + if (opt_debug && rc) { + timeval_subtract(&diff, &tv_end, &tv_start); + applog(LOG_DEBUG, "DEBUG: authenticated in %d ms", + diff.tv_sec * 1000 + diff.tv_usec / 1000); + } + + json_decref(val); +end: + return rc; } -static bool workio_login(CURL *curl) { - int failures = 0; - - /* submit solution to bitcoin via JSON-RPC */ - pthread_mutex_lock(&rpc2_login_lock); - while (!rpc2_login(curl)) { - if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { - applog(LOG_ERR, "...terminating workio thread"); - pthread_mutex_unlock(&rpc2_login_lock); - return false; - } - - /* pause, then restart work-request loop */ - applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause); - sleep(opt_fail_pause); - pthread_mutex_unlock(&rpc2_login_lock); - pthread_mutex_lock(&rpc2_login_lock); - } - pthread_mutex_unlock(&rpc2_login_lock); - - return true; +bool rpc2_workio_login(CURL *curl) +{ + int failures = 0; + if (opt_benchmark) + return true; + /* submit solution to bitcoin via JSON-RPC */ + pthread_mutex_lock(&rpc2_login_lock); + while (!rpc2_login(curl)) { + if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { + applog(LOG_ERR, "...terminating workio thread"); + pthread_mutex_unlock(&rpc2_login_lock); + return false; + } + + /* pause, then restart work-request loop */ + if (!opt_benchmark) + applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause); + sleep(opt_fail_pause); + pthread_mutex_unlock(&rpc2_login_lock); + pthread_mutex_lock(&rpc2_login_lock); + } + pthread_mutex_unlock(&rpc2_login_lock); + + return true; +} + +static void *workio_thread(void *userdata) +{ + struct thr_info *mythr = (struct thr_info *) userdata; + CURL *curl; + bool ok = true; + + curl = curl_easy_init(); + if (unlikely(!curl)) { + applog(LOG_ERR, "CURL initialization failed"); + return NULL; + } + + if(jsonrpc_2 && !have_stratum) { + ok = rpc2_workio_login(curl); + } + + while (ok) { + struct workio_cmd *wc; + + /* wait for workio_cmd sent to us, on our queue */ + wc = (struct workio_cmd *) tq_pop(mythr->q, NULL); + if (!wc) { + ok = false; + break; + } + + /* process workio_cmd */ + switch (wc->cmd) { + case WC_GET_WORK: + ok = workio_get_work(wc, curl); + break; + case WC_SUBMIT_WORK: + ok = workio_submit_work(wc, curl); + break; + + default: /* should never happen */ + ok = false; + break; + } + + workio_cmd_free(wc); + } + + tq_freeze(mythr->q); + curl_easy_cleanup(curl); + + return NULL; } -static void *workio_thread(void *userdata) { - struct thr_info *mythr = userdata; - CURL *curl; - bool ok = true; - - curl = curl_easy_init(); - if (unlikely(!curl)) { - applog(LOG_ERR, "CURL initialization failed"); - return NULL ; - } - - if(!have_stratum) { - ok = workio_login(curl); - } - - while (ok) { - struct workio_cmd *wc; - - /* wait for workio_cmd sent to us, on our queue */ - wc = tq_pop(mythr->q, NULL ); - if (!wc) { - ok = false; - break; - } - - /* process workio_cmd */ - switch (wc->cmd) { - case WC_GET_WORK: - ok = workio_get_work(wc, curl); - break; - case WC_SUBMIT_WORK: - ok = workio_submit_work(wc, curl); - break; - - default: /* should never happen */ - ok = false; - break; - } - - workio_cmd_free(wc); - } - - tq_freeze(mythr->q); - curl_easy_cleanup(curl); - - return NULL ; +static bool get_work(struct thr_info *thr, struct work *work) +{ + struct workio_cmd *wc; + struct work *work_heap; + + if (opt_benchmark) { + uint32_t ts = (uint32_t) time(NULL); + for (int n=0; n<74; n++) ((char*)work->data)[n] = n; + //memset(work->data, 0x55, 76); + work->data[17] = swab32(ts); + memset(work->data + 19, 0x00, 52); + if (opt_algo == ALGO_DECRED) { + memset(&work->data[35], 0x00, 52); + } else { + work->data[20] = 0x80000000; + work->data[31] = 0x00000280; + } + memset(work->target, 0x00, sizeof(work->target)); + return true; + } + + /* fill out work request message */ + wc = (struct workio_cmd *) calloc(1, sizeof(*wc)); + if (!wc) + return false; + + wc->cmd = WC_GET_WORK; + wc->thr = thr; + + /* send work request to workio thread */ + if (!tq_push(thr_info[work_thr_id].q, wc)) { + workio_cmd_free(wc); + return false; + } + + /* wait for response, a unit of work */ + work_heap = (struct work*) tq_pop(thr->q, NULL); + if (!work_heap) + return false; + + /* copy returned work into storage provided by caller */ + memcpy(work, work_heap, sizeof(*work)); + free(work_heap); + + return true; } -static bool get_work(struct thr_info *thr, struct work *work) { - struct workio_cmd *wc; - struct work *work_heap; - - if (opt_benchmark) { - memset(work->data, 0x55, 76); - work->data[17] = swab32(time(NULL )); - memset(work->data + 19, 0x00, 52); - work->data[20] = 0x80000000; - work->data[31] = 0x00000280; - memset(work->target, 0x00, sizeof(work->target)); - return true; - } - - /* fill out work request message */ - wc = calloc(1, sizeof(*wc)); - if (!wc) - return false; - - wc->cmd = WC_GET_WORK; - wc->thr = thr; - - /* send work request to workio thread */ - if (!tq_push(thr_info[work_thr_id].q, wc)) { - workio_cmd_free(wc); - return false; - } - - /* wait for response, a unit of work */ - work_heap = tq_pop(thr->q, NULL ); - if (!work_heap) - return false; - - /* copy returned work into storage provided by caller */ - memcpy(work, work_heap, sizeof(*work)); - free(work_heap); - - return true; +static bool submit_work(struct thr_info *thr, const struct work *work_in) +{ + struct workio_cmd *wc; + + /* fill out work request message */ + wc = (struct workio_cmd *) calloc(1, sizeof(*wc)); + if (!wc) + return false; + + wc->u.work = (struct work*) malloc(sizeof(*work_in)); + if (!wc->u.work) + goto err_out; + + wc->cmd = WC_SUBMIT_WORK; + wc->thr = thr; + work_copy(wc->u.work, work_in); + + /* send solution to workio thread */ + if (!tq_push(thr_info[work_thr_id].q, wc)) + goto err_out; + + return true; + +err_out: + workio_cmd_free(wc); + return false; } -static bool submit_work(struct thr_info *thr, const struct work *work_in) { - struct workio_cmd *wc; +static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) +{ + uint32_t extraheader[32] = { 0 }; + uchar merkle_root[64] = { 0 }; + int i, headersize = 0; - /* fill out work request message */ - wc = calloc(1, sizeof(*wc)); - if (!wc) - return false; + pthread_mutex_lock(&sctx->work_lock); - wc->u.work = malloc(sizeof(*work_in)); - if (!wc->u.work) - goto err_out; + if (jsonrpc_2) { + work_free(work); + work_copy(work, &sctx->work); + pthread_mutex_unlock(&sctx->work_lock); + } else { + free(work->job_id); + work->job_id = strdup(sctx->job.job_id); + work->xnonce2_len = sctx->xnonce2_size; + work->xnonce2 = (uchar*) realloc(work->xnonce2, sctx->xnonce2_size); + memcpy(work->xnonce2, sctx->job.xnonce2, sctx->xnonce2_size); + + /* Generate merkle root */ + switch (opt_algo) { + case ALGO_DECRED: + // getwork over stratum, getwork merkle + header passed in coinb1 + memcpy(merkle_root, sctx->job.coinbase, 32); + headersize = min((int)sctx->job.coinbase_size - 32, sizeof(extraheader)); + memcpy(extraheader, &sctx->job.coinbase[32], headersize); + break; + case ALGO_HEAVY: + heavyhash(merkle_root, sctx->job.coinbase, (int)sctx->job.coinbase_size); + break; + case ALGO_GROESTL: + case ALGO_KECCAK: + case ALGO_BLAKECOIN: + SHA256(sctx->job.coinbase, (int) sctx->job.coinbase_size, merkle_root); + break; + case ALGO_SIA: + // getwork over stratum, getwork merkle + header passed in coinb1 + memcpy(merkle_root, sctx->job.coinbase, 32); + headersize = min((int)sctx->job.coinbase_size - 32, sizeof(extraheader)); + memcpy(extraheader, &sctx->job.coinbase[32], headersize); + break; + default: + sha256d(merkle_root, sctx->job.coinbase, (int) sctx->job.coinbase_size); + } + + if (!headersize) + for (i = 0; i < sctx->job.merkle_count; i++) { + memcpy(merkle_root + 32, sctx->job.merkle[i], 32); + if (opt_algo == ALGO_HEAVY) + heavyhash(merkle_root, merkle_root, 64); + else + sha256d(merkle_root, merkle_root, 64); + } + + /* Increment extranonce2 */ + for (size_t t = 0; t < sctx->xnonce2_size && !(++sctx->job.xnonce2[t]); t++) + ; + + /* Assemble block header */ + memset(work->data, 0, 128); + work->data[0] = le32dec(sctx->job.version); + for (i = 0; i < 8; i++) + work->data[1 + i] = le32dec((uint32_t *) sctx->job.prevhash + i); + for (i = 0; i < 8; i++) + work->data[9 + i] = be32dec((uint32_t *) merkle_root + i); + + if (opt_algo == ALGO_DECRED) { + uint32_t* extradata = (uint32_t*) sctx->xnonce1; + for (i = 0; i < 8; i++) // prevhash + work->data[1 + i] = swab32(work->data[1 + i]); + for (i = 0; i < 8; i++) // merkle + work->data[9 + i] = swab32(work->data[9 + i]); + for (i = 0; i < headersize/4; i++) // header + work->data[17 + i] = extraheader[i]; + // extradata + for (i = 0; i < sctx->xnonce1_size/4; i++) + work->data[36 + i] = extradata[i]; + for (i = 36 + (int) sctx->xnonce1_size/4; i < 45; i++) + work->data[i] = 0; + work->data[37] = (rand()*4) << 8; + sctx->bloc_height = work->data[32]; + //applog_hex(work->data, 180); + //applog_hex(&work->data[36], 36); + } else if (opt_algo == ALGO_LBRY) { + for (i = 0; i < 8; i++) + work->data[17 + i] = ((uint32_t*)sctx->job.extra)[i]; + work->data[25] = le32dec(sctx->job.ntime); + work->data[26] = le32dec(sctx->job.nbits); + work->data[28] = 0x80000000; + } else if (opt_algo == ALGO_PHI2) { + work->data[17] = le32dec(sctx->job.ntime); + work->data[18] = le32dec(sctx->job.nbits); + for (i = 0; i < 16; i++) + work->data[20 + i] = ((uint32_t*)sctx->job.extra)[i]; + //applog_hex(&work->data[0], 144); + } else if (opt_algo == ALGO_SIA) { + for (i = 0; i < 8; i++) // prevhash + work->data[i] = ((uint32_t*)sctx->job.prevhash)[7-i]; + work->data[8] = 0; // nonce + work->data[9] = swab32(extraheader[0]); + work->data[9] |= rand() & 0xF0; + work->data[10] = be32dec(sctx->job.ntime); + work->data[11] = be32dec(sctx->job.nbits); + for (i = 0; i < 8; i++) // prevhash + work->data[12+i] = ((uint32_t*)merkle_root)[i]; + //applog_hex(&work->data[0], 80); + } else { + work->data[17] = le32dec(sctx->job.ntime); + work->data[18] = le32dec(sctx->job.nbits); + // required ? + work->data[20] = 0x80000000; + work->data[31] = 0x00000280; + } + + if (opt_showdiff || opt_max_diff > 0.) + calc_network_diff(work); + + if (opt_algo == ALGO_DROP || opt_algo == ALGO_NEOSCRYPT || opt_algo == ALGO_ZR5) { + /* reversed endian */ + for (i = 0; i <= 18; i++) + work->data[i] = swab32(work->data[i]); + } - wc->cmd = WC_SUBMIT_WORK; - wc->thr = thr; - work_copy(wc->u.work, work_in); + pthread_mutex_unlock(&sctx->work_lock); - /* send solution to workio thread */ - if (!tq_push(thr_info[work_thr_id].q, wc)) - goto err_out; + if (opt_debug && opt_algo != ALGO_DECRED && opt_algo != ALGO_SIA) { + char *xnonce2str = abin2hex(work->xnonce2, work->xnonce2_len); + applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x", + work->job_id, xnonce2str, swab32(work->data[17])); + free(xnonce2str); + } - return true; + switch (opt_algo) { + case ALGO_DROP: + case ALGO_JHA: + case ALGO_SCRYPT: + case ALGO_SCRYPTJANE: + case ALGO_NEOSCRYPT: + case ALGO_PLUCK: + case ALGO_YESCRYPT: + case ALGO_YESCRYPTR8: + case ALGO_YESCRYPTR16: + case ALGO_YESCRYPTR32: + work_set_target(work, sctx->job.diff / (65536.0 * opt_diff_factor)); + break; + case ALGO_ALLIUM: + case ALGO_FRESH: + case ALGO_DMD_GR: + case ALGO_GROESTL: + case ALGO_KECCAKC: + case ALGO_LBRY: + case ALGO_LYRA2REV2: + case ALGO_LYRA2V3: + case ALGO_PHI2: + case ALGO_TIMETRAVEL: + case ALGO_BITCORE: + case ALGO_XEVAN: + case ALGO_X16R: + case ALGO_X16RV2: + case ALGO_X16S: + case ALGO_X20R: + work_set_target(work, sctx->job.diff / (256.0 * opt_diff_factor)); + break; + case ALGO_KECCAK: + case ALGO_LYRA2: + work_set_target(work, sctx->job.diff / (128.0 * opt_diff_factor)); + break; + default: + work_set_target(work, sctx->job.diff / opt_diff_factor); + } - err_out: workio_cmd_free(wc); - return false; + if (stratum_diff != sctx->job.diff) { + char sdiff[32] = { 0 }; + // store for api stats + stratum_diff = sctx->job.diff; + if (opt_showdiff && work->targetdiff != stratum_diff) + snprintf(sdiff, 32, " (%.5f)", work->targetdiff); + applog(LOG_WARNING, "Stratum difficulty set to %g%s", stratum_diff, sdiff); + } + } } -static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) { - unsigned char merkle_root[64]; - int i; - - pthread_mutex_lock(&sctx->work_lock); - - if (jsonrpc_2) { - free(work->job_id); - memcpy(work, &sctx->work, sizeof(struct work)); - work->job_id = strdup(sctx->work.job_id); - pthread_mutex_unlock(&sctx->work_lock); - } else { - free(work->job_id); - work->job_id = strdup(sctx->job.job_id); - work->xnonce2_len = sctx->xnonce2_size; - work->xnonce2 = realloc(work->xnonce2, sctx->xnonce2_size); - memcpy(work->xnonce2, sctx->job.xnonce2, sctx->xnonce2_size); - - /* Generate merkle root */ - sha256d(merkle_root, sctx->job.coinbase, sctx->job.coinbase_size); - for (i = 0; i < sctx->job.merkle_count; i++) { - memcpy(merkle_root + 32, sctx->job.merkle[i], 32); - sha256d(merkle_root, merkle_root, 64); - } - - /* Increment extranonce2 */ - for (i = 0; i < sctx->xnonce2_size && !++sctx->job.xnonce2[i]; i++) - ; - - /* Assemble block header */ - memset(work->data, 0, 128); - work->data[0] = le32dec(sctx->job.version); - for (i = 0; i < 8; i++) - work->data[1 + i] = le32dec((uint32_t *) sctx->job.prevhash + i); - for (i = 0; i < 8; i++) - work->data[9 + i] = be32dec((uint32_t *) merkle_root + i); - work->data[17] = le32dec(sctx->job.ntime); - work->data[18] = le32dec(sctx->job.nbits); - work->data[20] = 0x80000000; - work->data[31] = 0x00000280; - - pthread_mutex_unlock(&sctx->work_lock); - - if (opt_debug) { - char *xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len); - applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x", - work->job_id, xnonce2str, swab32(work->data[17])); - free(xnonce2str); - } - - if (opt_algo == ALGO_SCRYPT) - diff_to_target(work->target, sctx->job.diff / 65536.0); - else - diff_to_target(work->target, sctx->job.diff); - } +bool rpc2_stratum_job(struct stratum_ctx *sctx, json_t *params) +{ + bool ret = false; + pthread_mutex_lock(&sctx->work_lock); + ret = rpc2_job_decode(params, &sctx->work); + + if (ret) { + work_free(&g_work); + work_copy(&g_work, &sctx->work); + g_work_time = 0; + } + + pthread_mutex_unlock(&sctx->work_lock); + + return ret; } -static void *miner_thread(void *userdata) { - struct thr_info *mythr = userdata; - int thr_id = mythr->id; - struct work work = { { 0 } }; - uint32_t max_nonce; - uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20; - unsigned char *scratchbuf = NULL; - char s[16]; - int i; - - /* Set worker threads to nice 19 and then preferentially to SCHED_IDLE - * and if that fails, then SCHED_BATCH. No need for this to be an - * error if it fails */ - if (!opt_benchmark) { - setpriority(PRIO_PROCESS, 0, 19); - drop_policy(); - } - - /* Cpu affinity only makes sense if the number of threads is a multiple - * of the number of CPUs */ - if (num_processors > 1 && opt_n_threads % num_processors == 0) { - if (!opt_quiet) - applog(LOG_INFO, "Binding thread %d to cpu %d", thr_id, - thr_id % num_processors); - affine_to_cpu(thr_id, thr_id % num_processors); - } - - if (opt_algo == ALGO_SCRYPT) { - scratchbuf = scrypt_buffer_alloc(opt_scrypt_n); - if (!scratchbuf) { - applog(LOG_ERR, "scrypt buffer allocation failed"); - pthread_mutex_lock(&applog_lock); - exit(1); - } - } - uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + (jsonrpc_2 ? 39 : 76)); - - while (1) { - uint64_t hashes_done; - struct timeval tv_start, tv_end, diff; - int64_t max64; - int rc; - - if (have_stratum) { - while (!jsonrpc_2 && time(NULL) >= g_work_time + 120) - sleep(1); - pthread_mutex_lock(&g_work_lock); - if ((*nonceptr) >= end_nonce - && !(jsonrpc_2 ? memcmp(work.data, g_work.data, 39) || - memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33) - : memcmp(work.data, g_work.data, 76))) - stratum_gen_work(&stratum, &g_work); - } else { - /* obtain new work from internal workio thread */ - pthread_mutex_lock(&g_work_lock); - if ((!have_stratum - && (!have_longpoll - || time(NULL ) >= g_work_time + LP_SCANTIME * 3 / 4 - || *nonceptr >= end_nonce))) { - if (unlikely(!get_work(mythr, &g_work))) { - applog(LOG_ERR, "work retrieval failed, exiting " - "mining thread %d", mythr->id); - pthread_mutex_unlock(&g_work_lock); - goto out; - } - g_work_time = have_stratum ? 0 : time(NULL ); - } - if (have_stratum) { - pthread_mutex_unlock(&g_work_lock); - continue; - } - } - if (jsonrpc_2 ? memcmp(work.data, g_work.data, 39) || memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33) : memcmp(work.data, g_work.data, 76)) { - work_free(&work); - work_copy(&work, &g_work); - nonceptr = (uint32_t*) (((char*)work.data) + (jsonrpc_2 ? 39 : 76)); - *nonceptr = 0xffffffffU / opt_n_threads * thr_id; - } else - ++(*nonceptr); - pthread_mutex_unlock(&g_work_lock); - work_restart[thr_id].restart = 0; - - /* adjust max_nonce to meet target scan time */ - if (have_stratum) - max64 = LP_SCANTIME; - else - max64 = g_work_time + (have_longpoll ? LP_SCANTIME : opt_scantime) - - time(NULL ); - max64 *= thr_hashrates[thr_id]; - if (max64 <= 0) { - switch (opt_algo) { - case ALGO_SCRYPT: - max64 = opt_scrypt_n < 16 ? 0x3ffff : 0x3fffff / opt_scrypt_n; - break; - case ALGO_CRYPTONIGHT: - max64 = 0x40LL; - break; - case ALGO_FRESH: - max64 = 0x3ffff; - break; - case ALGO_X13: - max64 = 0x1ffff; - break; - case ALGO_X14: - max64 = 0x3ffff; - break; - case ALGO_X15: - max64 = 0x1ffff; - break; - default: - max64 = 0x1fffffLL; - break; - } - } - if (*nonceptr + max64 > end_nonce) - max_nonce = end_nonce; - else - max_nonce = *nonceptr + max64; - - hashes_done = 0; - gettimeofday(&tv_start, NULL ); - - /* scan nonces for a proof-of-work hash */ - switch (opt_algo) { - case ALGO_SCRYPT: - rc = scanhash_scrypt(thr_id, work.data, scratchbuf, work.target, - max_nonce, &hashes_done, opt_scrypt_n); - break; - - case ALGO_SHA256D: - rc = scanhash_sha256d(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - - case ALGO_KECCAK: - rc = scanhash_keccak(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - - case ALGO_HEAVY: - rc = scanhash_heavy(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - - case ALGO_QUARK: - rc = scanhash_quark(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - - case ALGO_SKEIN: - rc = scanhash_skein(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_SHAVITE3: - rc = scanhash_ink(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_BLAKE: - rc = scanhash_blake(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_FRESH: - rc = scanhash_fresh(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_X11: - rc = scanhash_x11(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_X13: - rc = scanhash_x13(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_X14: - rc = scanhash_x14(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_X15: - rc = scanhash_x15(thr_id, work.data, work.target, max_nonce, - &hashes_done); - break; - case ALGO_CRYPTONIGHT: - rc = scanhash_cryptonight(thr_id, work.data, work.target, - max_nonce, &hashes_done); - break; - - default: - /* should never happen */ - goto out; - } - - /* record scanhash elapsed time */ - gettimeofday(&tv_end, NULL); - timeval_subtract(&diff, &tv_end, &tv_start); - if (diff.tv_usec || diff.tv_sec) { - pthread_mutex_lock(&stats_lock); - thr_hashrates[thr_id] = - hashes_done / (diff.tv_sec + diff.tv_usec * 1e-6); - pthread_mutex_unlock(&stats_lock); - } - if (!opt_quiet) { - switch(opt_algo) { - case ALGO_CRYPTONIGHT: - applog(LOG_INFO, "thread %d: %lu hashes, %.2f H/s", thr_id, - hashes_done, thr_hashrates[thr_id]); - break; - default: - sprintf(s, thr_hashrates[thr_id] >= 1e6 ? "%.0f" : "%.2f", - thr_hashrates[thr_id] / 1e3); - applog(LOG_INFO, "thread %d: %llu hashes, %s khash/s", thr_id, - hashes_done, s); - break; - } - } - if (opt_benchmark && thr_id == opt_n_threads - 1) { - double hashrate = 0.; - for (i = 0; i < opt_n_threads && thr_hashrates[i]; i++) - hashrate += thr_hashrates[i]; - if (i == opt_n_threads) { - switch(opt_algo) { - case ALGO_CRYPTONIGHT: - applog(LOG_INFO, "Total: %s H/s", hashrate); - break; - default: - sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000); - applog(LOG_INFO, "Total: %s khash/s", s); - break; - } - } - } - - /* if nonce found, submit work */ - if (rc && !opt_benchmark && !submit_work(mythr, &work)) - break; - } - - out: tq_freeze(mythr->q); - - return NULL ; +static bool wanna_mine(int thr_id) +{ + bool state = true; + + if (opt_max_temp > 0.0) { + float temp = cpu_temp(0); + if (temp > opt_max_temp) { + if (!thr_id && !conditional_state[thr_id] && !opt_quiet) + applog(LOG_INFO, "temperature too high (%.0fC), waiting...", temp); + state = false; + } + } + if (opt_max_diff > 0.0 && net_diff > opt_max_diff) { + if (!thr_id && !conditional_state[thr_id] && !opt_quiet) + applog(LOG_INFO, "network diff too high, waiting..."); + state = false; + } + if (opt_max_rate > 0.0 && net_hashrate > opt_max_rate) { + if (!thr_id && !conditional_state[thr_id] && !opt_quiet) { + char rate[32]; + format_hashrate(opt_max_rate, rate); + applog(LOG_INFO, "network hashrate too high, waiting %s...", rate); + } + state = false; + } + if (thr_id < MAX_CPUS) + conditional_state[thr_id] = (uint8_t) !state; + return state; } -static void restart_threads(void) { - int i; +static void *miner_thread(void *userdata) +{ + struct thr_info *mythr = (struct thr_info *) userdata; + int thr_id = mythr->id; + struct work work; + uint32_t max_nonce; + uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20; + time_t tm_rate_log = 0; + time_t firstwork_time = 0; + unsigned char *scratchbuf = NULL; + char s[16]; + int i; - for (i = 0; i < opt_n_threads; i++) - work_restart[i].restart = 1; + memset(&work, 0, sizeof(work)); + + /* Set worker threads to nice 19 and then preferentially to SCHED_IDLE + * and if that fails, then SCHED_BATCH. No need for this to be an + * error if it fails */ + if (!opt_benchmark && opt_priority == 0) { + setpriority(PRIO_PROCESS, 0, 19); + drop_policy(); + } else { + int prio = 0; +#ifndef WIN32 + prio = 18; + // note: different behavior on linux (-19 to 19) + switch (opt_priority) { + case 1: + prio = 5; + break; + case 2: + prio = 0; + break; + case 3: + prio = -5; + break; + case 4: + prio = -10; + break; + case 5: + prio = -15; + } + if (opt_debug) + applog(LOG_DEBUG, "Thread %d priority %d (nice %d)", + thr_id, opt_priority, prio); +#endif + setpriority(PRIO_PROCESS, 0, prio); + if (opt_priority == 0) { + drop_policy(); + } + } + + /* Cpu thread affinity */ + if (num_cpus > 1) { + if (opt_affinity == -1 && opt_n_threads > 1) { + if (opt_debug) + applog(LOG_DEBUG, "Binding thread %d to cpu %d (mask %x)", thr_id, + thr_id % num_cpus, (1 << (thr_id % num_cpus))); + affine_to_cpu_mask(thr_id, 1UL << (thr_id % num_cpus)); + } else if (opt_affinity != -1L) { + if (opt_debug) + applog(LOG_DEBUG, "Binding thread %d to cpu mask %x", thr_id, + opt_affinity); + affine_to_cpu_mask(thr_id, (unsigned long)opt_affinity); + } + } + + if (opt_algo == ALGO_SCRYPT) { + scratchbuf = scrypt_buffer_alloc(opt_scrypt_n); + if (!scratchbuf) { + applog(LOG_ERR, "scrypt buffer allocation failed"); + pthread_mutex_lock(&applog_lock); + exit(1); + } + } + + else if (opt_algo == ALGO_PLUCK) { + scratchbuf = malloc(opt_pluck_n * 1024); + if (!scratchbuf) { + applog(LOG_ERR, "pluck buffer allocation failed"); + pthread_mutex_lock(&applog_lock); + exit(1); + } + } + + while (1) { + uint64_t hashes_done; + struct timeval tv_start, tv_end, diff; + int64_t max64; + bool regen_work = false; + int wkcmp_offset = 0; + int nonce_oft = 19*sizeof(uint32_t); // 76 + int wkcmp_sz = nonce_oft; + int rc = 0; + + if (opt_algo == ALGO_DROP || opt_algo == ALGO_ZR5) { + // Duplicates: ignore pok in data[0] + wkcmp_sz -= sizeof(uint32_t); + wkcmp_offset = 1; + } else if (opt_algo == ALGO_DECRED) { + wkcmp_sz = nonce_oft = 140; // 35 * 4 + regen_work = true; // ntime not changed ? + } else if (opt_algo == ALGO_LBRY) { + wkcmp_sz = nonce_oft = 108; // 27 + //regen_work = true; + } else if (opt_algo == ALGO_SIA) { + nonce_oft = 32; + wkcmp_offset = 32 + 16; + wkcmp_sz = 32; // 35 * 4 + } + + if (jsonrpc_2) { + wkcmp_sz = nonce_oft = 39; + } + + uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + nonce_oft); + + if (have_stratum) { + while (!jsonrpc_2 && time(NULL) >= g_work_time + 120) + sleep(1); + + while (!stratum.job.diff && opt_algo == ALGO_NEOSCRYPT) { + applog(LOG_DEBUG, "Waiting for Stratum to set the job difficulty"); + sleep(1); + } + + pthread_mutex_lock(&g_work_lock); + + // to clean: is g_work loaded before the memcmp ? + regen_work = regen_work || ( (*nonceptr) >= end_nonce + && !( memcmp(&work.data[wkcmp_offset], &g_work.data[wkcmp_offset], wkcmp_sz) || + jsonrpc_2 ? memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33) : 0)); + if (regen_work) { + stratum_gen_work(&stratum, &g_work); + } + + } else { + + int min_scantime = have_longpoll ? LP_SCANTIME : opt_scantime; + /* obtain new work from internal workio thread */ + pthread_mutex_lock(&g_work_lock); + if (!have_stratum && + (time(NULL) - g_work_time >= min_scantime || + work.data[19] >= end_nonce)) { + if (unlikely(!get_work(mythr, &g_work))) { + applog(LOG_ERR, "work retrieval failed, exiting " + "mining thread %d", mythr->id); + pthread_mutex_unlock(&g_work_lock); + goto out; + } + g_work_time = have_stratum ? 0 : time(NULL); + } + if (have_stratum) { + pthread_mutex_unlock(&g_work_lock); + continue; + } + } + if (memcmp(&work.data[wkcmp_offset], &g_work.data[wkcmp_offset], wkcmp_sz) || + jsonrpc_2 ? memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33) : 0) + { + work_free(&work); + work_copy(&work, &g_work); + nonceptr = (uint32_t*) (((char*)work.data) + nonce_oft); + *nonceptr = 0xffffffffU / opt_n_threads * thr_id; + if (opt_randomize) + nonceptr[0] += ((rand()*4) & UINT32_MAX) / opt_n_threads; + } else + ++(*nonceptr); + pthread_mutex_unlock(&g_work_lock); + work_restart[thr_id].restart = 0; + + if (opt_algo == ALGO_DECRED) { + if (have_stratum && strcmp(stratum.job.job_id, work.job_id)) + continue; // need to regen g_work.. + // extradata: prevent duplicates + nonceptr[1] += 1; + nonceptr[2] |= thr_id; + } else if (opt_algo == ALGO_SIA) { + if (have_stratum && strcmp(stratum.job.job_id, work.job_id)) + continue; // need to regen g_work.. + // extradata: prevent duplicates + nonceptr[1] += 0x10; + nonceptr[1] |= thr_id; + //applog_hex(nonceptr, 8); + } + + // prevent scans before a job is received + // beware, some testnet (decred) are using version 0 + // no version in sia draft protocol + if (opt_algo != ALGO_SIA && have_stratum && !work.data[0] && !opt_benchmark) { + sleep(1); + continue; + } + + /* conditional mining */ + if (!wanna_mine(thr_id)) { + sleep(5); + continue; + } + + /* adjust max_nonce to meet target scan time */ + if (have_stratum) + max64 = LP_SCANTIME; + else + max64 = g_work_time + (have_longpoll ? LP_SCANTIME : opt_scantime) + - time(NULL); + + /* time limit */ + if (opt_time_limit && firstwork_time) { + int passed = (int)(time(NULL) - firstwork_time); + int remain = (int)(opt_time_limit - passed); + if (remain < 0) { + if (thr_id != 0) { + sleep(1); + continue; + } + if (opt_benchmark) { + char rate[32]; + format_hashrate((double)global_hashrate, rate); + applog(LOG_NOTICE, "Benchmark: %s", rate); + fprintf(stderr, "%llu\n", (long long unsigned int) global_hashrate); + } else { + applog(LOG_NOTICE, + "Mining timeout of %ds reached, exiting...", opt_time_limit); + } + proper_exit(0); + } + if (remain < max64) max64 = remain; + } + + max64 *= (int64_t) thr_hashrates[thr_id]; + + if (max64 <= 0) { + switch (opt_algo) { + case ALGO_SCRYPT: + case ALGO_NEOSCRYPT: + max64 = opt_scrypt_n < 16 ? 0x3ffff : 0x3fffff / opt_scrypt_n; + if (opt_nfactor > 3) + max64 >>= (opt_nfactor - 3); + else if (opt_nfactor > 16) + max64 = 0xF; + break; + case ALGO_AXIOM: + case ALGO_CRYPTOLIGHT: + case ALGO_CRYPTONIGHT: + case ALGO_SCRYPTJANE: + max64 = 0x40LL; + break; + case ALGO_DROP: + case ALGO_PLUCK: + case ALGO_YESCRYPT: + case ALGO_YESCRYPTR8: + max64 = 0x1ff; + break; + case ALGO_YESCRYPTR16: + case ALGO_YESCRYPTR32: + max64 = 0xfff; + break; + case ALGO_ALLIUM: + case ALGO_LYRA2: + case ALGO_LYRA2REV2: + case ALGO_LYRA2V3: + case ALGO_PHI1612: + case ALGO_PHI2: + case ALGO_TIMETRAVEL: + case ALGO_BITCORE: + case ALGO_XEVAN: + max64 = 0xffff; + break; + case ALGO_C11: + case ALGO_DMD_GR: + case ALGO_FRESH: + case ALGO_GEEK: + case ALGO_GROESTL: + case ALGO_MYR_GR: + case ALGO_SIB: + case ALGO_VELTOR: + case ALGO_X11EVO: + case ALGO_X11: + case ALGO_X12: + case ALGO_X13: + case ALGO_X14: + max64 = 0x3ffff; + break; + case ALGO_LBRY: + case ALGO_SONOA: + case ALGO_TRIBUS: + case ALGO_X15: + case ALGO_X16R: + case ALGO_X16RV2: + case ALGO_X16S: + case ALGO_X17: + case ALGO_X20R: + case ALGO_ZR5: + max64 = 0x1ffff; + break; + case ALGO_BMW: + case ALGO_PENTABLAKE: + max64 = 0x3ffff; + break; + case ALGO_SKEIN: + case ALGO_SKEIN2: + max64 = 0x7ffffLL; + break; + case ALGO_BLAKE: + case ALGO_BLAKECOIN: + case ALGO_DECRED: + case ALGO_VANILLA: + max64 = 0x3fffffLL; + break; + case ALGO_SIA: + default: + max64 = 0x1fffffLL; + break; + } + } + if ((*nonceptr) + max64 > end_nonce) + max_nonce = end_nonce; + else + max_nonce = (*nonceptr) + (uint32_t) max64; + + hashes_done = 0; + gettimeofday((struct timeval *) &tv_start, NULL); + + if (firstwork_time == 0) + firstwork_time = time(NULL); + + /* scan nonces for a proof-of-work hash */ + switch (opt_algo) { + + case ALGO_ALLIUM: + rc = scanhash_allium(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_AXIOM: + rc = scanhash_axiom(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BASTION: + rc = scanhash_bastion(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BLAKE: + rc = scanhash_blake(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BLAKECOIN: + rc = scanhash_blakecoin(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BLAKE2B: + rc = scanhash_blake2b(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BLAKE2S: + rc = scanhash_blake2s(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BMW: + rc = scanhash_bmw(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_C11: + rc = scanhash_c11(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_CRYPTOLIGHT: + rc = scanhash_cryptolight(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_CRYPTONIGHT: + rc = scanhash_cryptonight(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_DECRED: + rc = scanhash_decred(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_DROP: + rc = scanhash_drop(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_FRESH: + rc = scanhash_fresh(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_GEEK: + rc = scanhash_geek(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_DMD_GR: + case ALGO_GROESTL: + rc = scanhash_groestl(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_KECCAK: + case ALGO_KECCAKC: + rc = scanhash_keccak(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_HEAVY: + rc = scanhash_heavy(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_JHA: + rc = scanhash_jha(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_LBRY: + rc = scanhash_lbry(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_LUFFA: + rc = scanhash_luffa(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_LYRA2: + rc = scanhash_lyra2(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_LYRA2REV2: + rc = scanhash_lyra2rev2(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_LYRA2V3: + rc = scanhash_lyra2v3(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_MYR_GR: + rc = scanhash_myriad(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_NEOSCRYPT: + rc = scanhash_neoscrypt(thr_id, &work, max_nonce, &hashes_done, + 0x80000020 | (opt_nfactor << 8)); + break; + case ALGO_NIST5: + rc = scanhash_nist5(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_PENTABLAKE: + rc = scanhash_pentablake(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_PHI1612: + rc = scanhash_phi1612(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_PHI2: + rc = scanhash_phi2(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_PLUCK: + rc = scanhash_pluck(thr_id, &work, max_nonce, &hashes_done, scratchbuf, opt_pluck_n); + break; + case ALGO_QUARK: + rc = scanhash_quark(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_QUBIT: + rc = scanhash_qubit(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_RAINFOREST: + rc = scanhash_rf256(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SCRYPT: + rc = scanhash_scrypt(thr_id, &work, max_nonce, &hashes_done, scratchbuf, opt_scrypt_n); + break; + case ALGO_SCRYPTJANE: + rc = scanhash_scryptjane(opt_scrypt_n, thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SHAVITE3: + rc = scanhash_ink(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SHA256D: + rc = scanhash_sha256d(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SIA: + rc = scanhash_sia(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SIB: + rc = scanhash_sib(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SKEIN: + rc = scanhash_skein(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SKEIN2: + rc = scanhash_skein2(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_SONOA: + rc = scanhash_sonoa(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_S3: + rc = scanhash_s3(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_TIMETRAVEL: + rc = scanhash_timetravel(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_BITCORE: + rc = scanhash_bitcore(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_TRIBUS: + rc = scanhash_tribus(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_VANILLA: + rc = scanhash_blakecoin(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_VELTOR: + rc = scanhash_veltor(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X11EVO: + rc = scanhash_x11evo(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X11: + rc = scanhash_x11(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X12: + rc = scanhash_x12(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X13: + rc = scanhash_x13(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X14: + rc = scanhash_x14(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X15: + rc = scanhash_x15(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X16R: + rc = scanhash_x16r(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X16RV2: + rc = scanhash_x16rv2(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X20R: + rc = scanhash_x20r(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X16S: + rc = scanhash_x16s(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_X17: + rc = scanhash_x17(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_XEVAN: + rc = scanhash_xevan(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_YESCRYPT: + rc = scanhash_yescrypt(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_YESCRYPTR8: + rc = scanhash_yescryptr8(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_YESCRYPTR16: + rc = scanhash_yescryptr16(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_YESCRYPTR32: + rc = scanhash_yescryptr32(thr_id, &work, max_nonce, &hashes_done); + break; + case ALGO_ZR5: + rc = scanhash_zr5(thr_id, &work, max_nonce, &hashes_done); + break; + default: + /* should never happen */ + goto out; + } + + /* record scanhash elapsed time */ + gettimeofday(&tv_end, NULL); + timeval_subtract(&diff, &tv_end, &tv_start); + if (diff.tv_usec || diff.tv_sec) { + pthread_mutex_lock(&stats_lock); + thr_hashrates[thr_id] = + hashes_done / (diff.tv_sec + diff.tv_usec * 1e-6); + pthread_mutex_unlock(&stats_lock); + } + if (!opt_quiet && (time(NULL) - tm_rate_log) > opt_maxlograte) { + switch(opt_algo) { + case ALGO_AXIOM: + case ALGO_CRYPTOLIGHT: + case ALGO_CRYPTONIGHT: + case ALGO_PLUCK: + case ALGO_SCRYPTJANE: + applog(LOG_INFO, "CPU #%d: %.2f H/s", thr_id, thr_hashrates[thr_id]); + break; + default: + sprintf(s, thr_hashrates[thr_id] >= 1e6 ? "%.0f" : "%.2f", + thr_hashrates[thr_id] / 1e3); + applog(LOG_INFO, "CPU #%d: %s kH/s", thr_id, s); + break; + } + tm_rate_log = time(NULL); + } + if (opt_benchmark && thr_id == opt_n_threads - 1) { + double hashrate = 0.; + for (i = 0; i < opt_n_threads && thr_hashrates[i]; i++) + hashrate += thr_hashrates[i]; + if (i == opt_n_threads) { + switch(opt_algo) { + case ALGO_CRYPTOLIGHT: + case ALGO_CRYPTONIGHT: + case ALGO_AXIOM: + case ALGO_SCRYPTJANE: + sprintf(s, "%.3f", hashrate); + applog(LOG_NOTICE, "Total: %s H/s", s); + break; + default: + sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000); + applog(LOG_NOTICE, "Total: %s kH/s", s); + break; + } + global_hashrate = (uint64_t) hashrate; + } + } + + /* if nonce found, submit work */ + if (rc && !opt_benchmark) { + if (!submit_work(mythr, &work)) + break; + // prevent stale work in solo + // we can't submit twice a block! + if (!have_stratum && !have_longpoll) { + pthread_mutex_lock(&g_work_lock); + // will force getwork + g_work_time = 0; + pthread_mutex_unlock(&g_work_lock); + continue; + } + } + + } + +out: + tq_freeze(mythr->q); + + return NULL; } -static void *longpoll_thread(void *userdata) { - struct thr_info *mythr = userdata; - CURL *curl = NULL; - char *copy_start, *hdr_path = NULL, *lp_url = NULL; - bool need_slash = false; - - curl = curl_easy_init(); - if (unlikely(!curl)) { - applog(LOG_ERR, "CURL initialization failed"); - goto out; - } - - start: hdr_path = tq_pop(mythr->q, NULL ); - if (!hdr_path) - goto out; - - /* full URL */ - if (strstr(hdr_path, "://")) { - lp_url = hdr_path; - hdr_path = NULL; - } - - /* absolute path, on current server */ - else { - copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path; - if (rpc_url[strlen(rpc_url) - 1] != '/') - need_slash = true; - - lp_url = malloc(strlen(rpc_url) + strlen(copy_start) + 2); - if (!lp_url) - goto out; - - sprintf(lp_url, "%s%s%s", rpc_url, need_slash ? "/" : "", copy_start); - } - - applog(LOG_INFO, "Long-polling activated for %s", lp_url); - - while (1) { - json_t *val, *soval; - int err; - - if(jsonrpc_2) { - pthread_mutex_lock(&rpc2_login_lock); - if(!strcmp(rpc2_id, "")) { - sleep(1); - continue; - } - char s[128]; - snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id); - pthread_mutex_unlock(&rpc2_login_lock); - val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, &err, JSON_RPC_LONGPOLL); - } else { - val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req, &err, JSON_RPC_LONGPOLL); - } - if (have_stratum) { - if (val) - json_decref(val); - goto out; - } - if (likely(val)) { - if (!jsonrpc_2) { - soval = json_object_get(json_object_get(val, "result"), - "submitold"); - submit_old = soval ? json_is_true(soval) : false; - } - pthread_mutex_lock(&g_work_lock); - char *start_job_id = strdup(g_work.job_id); - if (work_decode(json_object_get(val, "result"), &g_work)) { - if (strcmp(start_job_id, g_work.job_id)) { - applog(LOG_INFO, "LONGPOLL detected new block"); - if (opt_debug) - applog(LOG_DEBUG, "DEBUG: got new work"); - time(&g_work_time); - restart_threads(); - } - } - free(start_job_id); - pthread_mutex_unlock(&g_work_lock); - json_decref(val); - } else { - pthread_mutex_lock(&g_work_lock); - g_work_time -= LP_SCANTIME; - pthread_mutex_unlock(&g_work_lock); - if (err == CURLE_OPERATION_TIMEDOUT) { - restart_threads(); - } else { - have_longpoll = false; - restart_threads(); - free(hdr_path); - free(lp_url); - lp_url = NULL; - sleep(opt_fail_pause); - goto start; - } - } - } - - out: free(hdr_path); - free(lp_url); - tq_freeze(mythr->q); - if (curl) - curl_easy_cleanup(curl); - - return NULL ; +void restart_threads(void) +{ + int i; + + for (i = 0; i < opt_n_threads; i++) + work_restart[i].restart = 1; } -static bool stratum_handle_response(char *buf) { - json_t *val, *err_val, *res_val, *id_val; - json_error_t err; - bool ret = false; - bool valid = false; - - val = JSON_LOADS(buf, &err); - if (!val) { - applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); - goto out; - } - - res_val = json_object_get(val, "result"); - err_val = json_object_get(val, "error"); - id_val = json_object_get(val, "id"); - - if (!id_val || json_is_null(id_val) || !res_val) - goto out; - - if(jsonrpc_2) { - json_t *status = json_object_get(res_val, "status"); - if(status) { - const char *s = json_string_value(status); - valid = !strcmp(s, "OK") && json_is_null(err_val); - } else { - valid = json_is_null(err_val); - } - } else { - valid = json_is_true(res_val); - } - - share_result(valid, NULL, - err_val ? (jsonrpc_2 ? json_string_value(err_val) : json_string_value(json_array_get(err_val, 1))) : NULL ); - - ret = true; - out: if (val) - json_decref(val); - - return ret; +static void *longpoll_thread(void *userdata) +{ + struct thr_info *mythr = (struct thr_info*) userdata; + CURL *curl = NULL; + char *copy_start, *hdr_path = NULL, *lp_url = NULL; + bool need_slash = false; + + curl = curl_easy_init(); + if (unlikely(!curl)) { + applog(LOG_ERR, "CURL init failed"); + goto out; + } + +start: + hdr_path = (char*) tq_pop(mythr->q, NULL); + if (!hdr_path) + goto out; + + /* full URL */ + if (strstr(hdr_path, "://")) { + lp_url = hdr_path; + hdr_path = NULL; + } + + /* absolute path, on current server */ + else { + copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path; + if (rpc_url[strlen(rpc_url) - 1] != '/') + need_slash = true; + + lp_url = (char*) malloc(strlen(rpc_url) + strlen(copy_start) + 2); + if (!lp_url) + goto out; + + sprintf(lp_url, "%s%s%s", rpc_url, need_slash ? "/" : "", copy_start); + } + + if (!opt_quiet) + applog(LOG_BLUE, "Long-polling on %s", lp_url); + + while (1) { + json_t *val; + char *req = NULL; + int err; + + if (jsonrpc_2) { + char s[128]; + pthread_mutex_lock(&rpc2_login_lock); + if (!strlen(rpc2_id)) { + sleep(1); + continue; + } + snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id); + pthread_mutex_unlock(&rpc2_login_lock); + val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, &err, JSON_RPC_LONGPOLL); + } else { + if (have_gbt) { + req = (char*) malloc(strlen(gbt_lp_req) + strlen(lp_id) + 1); + sprintf(req, gbt_lp_req, lp_id); + } + val = json_rpc_call(curl, rpc_url, rpc_userpass, getwork_req, &err, JSON_RPC_LONGPOLL); + val = json_rpc_call(curl, lp_url, rpc_userpass, + req ? req : getwork_req, &err, + JSON_RPC_LONGPOLL); + free(req); + } + + if (have_stratum) { + if (val) + json_decref(val); + goto out; + } + if (likely(val)) { + bool rc; + char *start_job_id; + double start_diff = 0.0; + json_t *res, *soval; + res = json_object_get(val, "result"); + if (!jsonrpc_2) { + soval = json_object_get(res, "submitold"); + submit_old = soval ? json_is_true(soval) : false; + } + pthread_mutex_lock(&g_work_lock); + start_job_id = g_work.job_id ? strdup(g_work.job_id) : NULL; + if (have_gbt) + rc = gbt_work_decode(res, &g_work); + else + rc = work_decode(res, &g_work); + if (rc) { + bool newblock = g_work.job_id && strcmp(start_job_id, g_work.job_id); + newblock |= (start_diff != net_diff); // the best is the height but... longpoll... + if (newblock) { + start_diff = net_diff; + if (!opt_quiet) { + char netinfo[64] = { 0 }; + if (net_diff > 0.) { + sprintf(netinfo, ", diff %.3f", net_diff); + } + if (opt_showdiff) + sprintf(&netinfo[strlen(netinfo)], ", target %.3f", g_work.targetdiff); + applog(LOG_BLUE, "%s detected new block%s", short_url, netinfo); + } + time(&g_work_time); + restart_threads(); + } + } + free(start_job_id); + pthread_mutex_unlock(&g_work_lock); + json_decref(val); + } else { + pthread_mutex_lock(&g_work_lock); + g_work_time -= LP_SCANTIME; + pthread_mutex_unlock(&g_work_lock); + if (err == CURLE_OPERATION_TIMEDOUT) { + restart_threads(); + } else { + have_longpoll = false; + restart_threads(); + free(hdr_path); + free(lp_url); + lp_url = NULL; + sleep(opt_fail_pause); + goto start; + } + } + } + +out: + free(hdr_path); + free(lp_url); + tq_freeze(mythr->q); + if (curl) + curl_easy_cleanup(curl); + + return NULL; +} + +static bool stratum_handle_response(char *buf) +{ + json_t *val, *err_val, *res_val, *id_val; + json_error_t err; + bool ret = false; + bool valid = false; + + val = JSON_LOADS(buf, &err); + if (!val) { + applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); + goto out; + } + + res_val = json_object_get(val, "result"); + err_val = json_object_get(val, "error"); + id_val = json_object_get(val, "id"); + + if (!id_val || json_is_null(id_val)) + goto out; + + if (jsonrpc_2) + { + if (!res_val && !err_val) + goto out; + + json_t *status = json_object_get(res_val, "status"); + if(status) { + const char *s = json_string_value(status); + valid = !strcmp(s, "OK") && json_is_null(err_val); + } else { + valid = json_is_null(err_val); + } + share_result(valid, NULL, err_val ? json_string_value(err_val) : NULL); + + } else { + + if (!res_val || json_integer_value(id_val) < 4) + goto out; + valid = json_is_true(res_val); + share_result(valid, NULL, err_val ? json_string_value(json_array_get(err_val, 1)) : NULL); + } + + ret = true; + +out: + if (val) + json_decref(val); + + return ret; } -static void *stratum_thread(void *userdata) { - struct thr_info *mythr = userdata; - char *s; - - stratum.url = tq_pop(mythr->q, NULL ); - if (!stratum.url) - goto out; - applog(LOG_INFO, "Starting Stratum on %s", stratum.url); - - while (1) { - int failures = 0; - - while (!stratum.curl) { - pthread_mutex_lock(&g_work_lock); - g_work_time = 0; - pthread_mutex_unlock(&g_work_lock); - restart_threads(); - - if (!stratum_connect(&stratum, stratum.url) - || !stratum_subscribe(&stratum) - || !stratum_authorize(&stratum, rpc_user, rpc_pass)) { - stratum_disconnect(&stratum); - if (opt_retries >= 0 && ++failures > opt_retries) { - applog(LOG_ERR, "...terminating workio thread"); - tq_push(thr_info[work_thr_id].q, NULL ); - goto out; - } - applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause); - sleep(opt_fail_pause); - } - } - - if (jsonrpc_2) { - if (stratum.work.job_id - && (!g_work_time - || strcmp(stratum.work.job_id, g_work.job_id))) { - pthread_mutex_lock(&g_work_lock); - stratum_gen_work(&stratum, &g_work); - time(&g_work_time); - pthread_mutex_unlock(&g_work_lock); - applog(LOG_INFO, "Stratum detected new block"); - restart_threads(); - } - } else { - if (stratum.job.job_id - && (!g_work_time - || strcmp(stratum.job.job_id, g_work.job_id))) { - pthread_mutex_lock(&g_work_lock); - stratum_gen_work(&stratum, &g_work); - time(&g_work_time); - pthread_mutex_unlock(&g_work_lock); - if (stratum.job.clean) { - applog(LOG_INFO, "Stratum detected new block"); - restart_threads(); - } - } - } - - if (!stratum_socket_full(&stratum, 120)) { - applog(LOG_ERR, "Stratum connection timed out"); - s = NULL; - } else - s = stratum_recv_line(&stratum); - if (!s) { - stratum_disconnect(&stratum); - applog(LOG_ERR, "Stratum connection interrupted"); - continue; - } - if (!stratum_handle_method(&stratum, s)) - stratum_handle_response(s); - free(s); - } - - out: return NULL ; +static void *stratum_thread(void *userdata) +{ + struct thr_info *mythr = (struct thr_info *) userdata; + char *s; + + stratum.url = (char*) tq_pop(mythr->q, NULL); + if (!stratum.url) + goto out; + applog(LOG_INFO, "Starting Stratum on %s", stratum.url); + + while (1) { + int failures = 0; + + if (stratum_need_reset) { + stratum_need_reset = false; + stratum_disconnect(&stratum); + if (strcmp(stratum.url, rpc_url)) { + free(stratum.url); + stratum.url = strdup(rpc_url); + applog(LOG_BLUE, "Connection changed to %s", short_url); + } else if (!opt_quiet) { + applog(LOG_DEBUG, "Stratum connection reset"); + } + } + + while (!stratum.curl) { + pthread_mutex_lock(&g_work_lock); + g_work_time = 0; + pthread_mutex_unlock(&g_work_lock); + restart_threads(); + + if (!stratum_connect(&stratum, stratum.url) + || !stratum_subscribe(&stratum) + || !stratum_authorize(&stratum, rpc_user, rpc_pass)) { + stratum_disconnect(&stratum); + if (opt_retries >= 0 && ++failures > opt_retries) { + applog(LOG_ERR, "...terminating workio thread"); + tq_push(thr_info[work_thr_id].q, NULL); + goto out; + } + if (!opt_benchmark) + applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause); + sleep(opt_fail_pause); + } + + if (jsonrpc_2) { + work_free(&g_work); + work_copy(&g_work, &stratum.work); + } + } + + if (stratum.job.job_id && + (!g_work_time || strcmp(stratum.job.job_id, g_work.job_id)) ) + { + pthread_mutex_lock(&g_work_lock); + stratum_gen_work(&stratum, &g_work); + time(&g_work_time); + pthread_mutex_unlock(&g_work_lock); + + if (stratum.job.clean || jsonrpc_2) { + static uint32_t last_bloc_height; + if (!opt_quiet && last_bloc_height != stratum.bloc_height) { + last_bloc_height = stratum.bloc_height; + if (net_diff > 0.) + applog(LOG_BLUE, "%s block %d, diff %.3f", algo_names[opt_algo], + stratum.bloc_height, net_diff); + else + applog(LOG_BLUE, "%s %s block %d", short_url, algo_names[opt_algo], + stratum.bloc_height); + } + restart_threads(); + } else if (opt_debug && !opt_quiet) { + applog(LOG_BLUE, "%s asks job %lu for block %d", short_url, + strtoul(stratum.job.job_id, NULL, 16), stratum.bloc_height); + } + } + + if (!stratum_socket_full(&stratum, opt_timeout)) { + applog(LOG_ERR, "Stratum connection timeout"); + s = NULL; + } else + s = stratum_recv_line(&stratum); + if (!s) { + stratum_disconnect(&stratum); + applog(LOG_ERR, "Stratum connection interrupted"); + continue; + } + if (!stratum_handle_method(&stratum, s)) + stratum_handle_response(s); + free(s); + } +out: + return NULL; } -static void show_version_and_exit(void) { - printf(PACKAGE_STRING "\n built on " __DATE__ "\n features:" +static void show_version_and_exit(void) +{ + printf(" built " +#ifdef _MSC_VER + "with VC++ %d", msver()); +#elif defined(__GNUC__) + "with GCC "); + printf("%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +#endif + printf(" the " __DATE__ "\n"); + + // Note: if compiled with cpu opts (instruction sets), + // the binary is no more compatible with older ones! + printf(" compiled for" +#if defined(__ARM_NEON__) + " ARM NEON" +#elif defined(__AVX2__) + " AVX2" +#elif defined(__AVX__) + " AVX" +#elif defined(__XOP__) + " XOP" +#elif defined(__SSE4_1__) + " SSE4" +#elif defined(_M_X64) || defined(__x86_64__) + " x64" +#elif defined(_M_IX86) || defined(__x86__) + " x86" +#else + " general use" +#endif + "\n"); + + printf(" config features:" #if defined(USE_ASM) && defined(__i386__) - " i386" + " i386" #endif #if defined(USE_ASM) && defined(__x86_64__) - " x86_64" + " x86_64" #endif -#if defined(USE_ASM) && defined(__i386__) || defined(__x86_64__) - " SSE2" +#if defined(USE_ASM) && (defined(__i386__) || defined(__x86_64__)) + " SSE2" +#endif +#if defined(__x86_64__) && defined(USE_XOP) + " XOP" #endif #if defined(__x86_64__) && defined(USE_AVX) - " AVX" + " AVX" #endif #if defined(__x86_64__) && defined(USE_AVX2) - " AVX2" -#endif -#if defined(__x86_64__) && defined(USE_XOP) - " XOP" + " AVX2" #endif #if defined(USE_ASM) && defined(__arm__) && defined(__APCS_32__) - " ARM" + " ARM" #if defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || \ defined(__ARM_ARCH_5TEJ__) || defined(__ARM_ARCH_6__) || \ defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || \ @@ -1534,347 +2911,634 @@ static void show_version_and_exit(void) { defined(__ARM_ARCH_7__) || \ defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) - " ARMv5E" + " ARMv5E" #endif #if defined(__ARM_NEON__) - " NEON" + " NEON" #endif #endif - "\n"); - - printf("%s\n", curl_version()); + "\n\n"); + /* dependencies versions */ + printf("%s\n", curl_version()); #ifdef JANSSON_VERSION - printf("libjansson %s\n", JANSSON_VERSION); + printf("jansson/%s ", JANSSON_VERSION); +#endif +#ifdef PTW32_VERSION + printf("pthreads/%d.%d.%d.%d ", PTW32_VERSION); #endif - exit(0); + printf("\n"); + exit(0); } -static void show_usage_and_exit(int status) { - if (status) - fprintf(stderr, - "Try `" PROGRAM_NAME " --help' for more information.\n"); - else - printf(usage); - exit(status); +static void show_usage_and_exit(int status) +{ + if (status) + fprintf(stderr, "Try `" PACKAGE_NAME " --help' for more information.\n"); + else + printf(usage); + exit(status); } -static void parse_arg(int key, char *arg) { - char *p; - int v, i; - - switch (key) { - case 'a': - for (i = 0; i < ARRAY_SIZE(algo_names); i++) { - v = strlen(algo_names[i]); - if (!strncmp(arg, algo_names[i], v)) { - if (arg[v] == '\0') { - opt_algo = i; - break; - } - if (arg[v] == ':' && i == ALGO_SCRYPT) { - char *ep; - v = strtol(arg+v+1, &ep, 10); - if (*ep || v & (v-1) || v < 2) - continue; - opt_algo = i; - opt_scrypt_n = v; - break; - } - } - } - if (i == ARRAY_SIZE(algo_names)) - show_usage_and_exit(1); - break; - case 'B': - opt_background = true; - break; - case 'c': { - json_error_t err; - if (opt_config) - json_decref(opt_config); -#if JANSSON_VERSION_HEX >= 0x020000 - opt_config = json_load_file(arg, 0, &err); -#else - opt_config = json_load_file(arg, &err); -#endif - if (!json_is_object(opt_config)) { - applog(LOG_ERR, "JSON decode of %s failed", arg); - exit(1); - } - break; - } - case 'q': - opt_quiet = true; - break; - case 'D': - opt_debug = true; - break; - case 'p': - free(rpc_pass); - rpc_pass = strdup(arg); - break; - case 'P': - opt_protocol = true; - break; - case 'r': - v = atoi(arg); - if (v < -1 || v > 9999) /* sanity check */ - show_usage_and_exit(1); - opt_retries = v; - break; - case 'R': - v = atoi(arg); - if (v < 1 || v > 9999) /* sanity check */ - show_usage_and_exit(1); - opt_fail_pause = v; - break; - case 's': - v = atoi(arg); - if (v < 1 || v > 9999) /* sanity check */ - show_usage_and_exit(1); - opt_scantime = v; - break; - case 'T': - v = atoi(arg); - if (v < 1 || v > 99999) /* sanity check */ - show_usage_and_exit(1); - opt_timeout = v; - break; - case 't': - v = atoi(arg); - if (v < 1 || v > 9999) /* sanity check */ - show_usage_and_exit(1); - opt_n_threads = v; - break; - case 'u': - free(rpc_user); - rpc_user = strdup(arg); - break; - case 'o': /* --url */ - p = strstr(arg, "://"); - if (p) { - if (strncasecmp(arg, "http://", 7) - && strncasecmp(arg, "https://", 8) - && strncasecmp(arg, "stratum+tcp://", 14)) - show_usage_and_exit(1); - free(rpc_url); - rpc_url = strdup(arg); - } else { - if (!strlen(arg) || *arg == '/') - show_usage_and_exit(1); - free(rpc_url); - rpc_url = malloc(strlen(arg) + 8); - sprintf(rpc_url, "http://%s", arg); - } - p = strrchr(rpc_url, '@'); - if (p) { - char *sp, *ap; - *p = '\0'; - ap = strstr(rpc_url, "://") + 3; - sp = strchr(ap, ':'); - if (sp) { - free(rpc_userpass); - rpc_userpass = strdup(ap); - free(rpc_user); - rpc_user = calloc(sp - ap + 1, 1); - strncpy(rpc_user, ap, sp - ap); - free(rpc_pass); - rpc_pass = strdup(sp + 1); - } else { - free(rpc_user); - rpc_user = strdup(ap); - } - memmove(ap, p + 1, strlen(p + 1) + 1); - } - have_stratum = !opt_benchmark && !strncasecmp(rpc_url, "stratum", 7); - break; - case 'O': /* --userpass */ - p = strchr(arg, ':'); - if (!p) - show_usage_and_exit(1); - free(rpc_userpass); - rpc_userpass = strdup(arg); - free(rpc_user); - rpc_user = calloc(p - arg + 1, 1); - strncpy(rpc_user, arg, p - arg); - free(rpc_pass); - rpc_pass = strdup(p + 1); - break; - case 'x': /* --proxy */ - if (!strncasecmp(arg, "socks4://", 9)) - opt_proxy_type = CURLPROXY_SOCKS4; - else if (!strncasecmp(arg, "socks5://", 9)) - opt_proxy_type = CURLPROXY_SOCKS5; +static void strhide(char *s) +{ + if (*s) *s++ = 'x'; + while (*s) *s++ = '\0'; +} + +void parse_arg(int key, char *arg) +{ + char *p; + int v, i; + uint64_t ul; + double d; + + switch(key) { + case 'a': + for (i = 0; i < ALGO_COUNT; i++) { + v = (int) strlen(algo_names[i]); + if (v && !strncasecmp(arg, algo_names[i], v)) { + if (arg[v] == '\0') { + opt_algo = (enum algos) i; + break; + } + if (arg[v] == ':') { + char *ep; + v = strtol(arg+v+1, &ep, 10); + if (*ep || (i == ALGO_SCRYPT && v & (v-1)) || v < 2) + continue; + opt_algo = (enum algos) i; + opt_scrypt_n = v; + break; + } + } + } + + if (i == ALGO_COUNT) { + + if (strstr(arg, ":")) { + // pick and strip the optional factor + char *nf = strstr(arg, ":"); + opt_scrypt_n = strtol(&nf[1], NULL, 10); + *nf = '\0'; + } + + // some aliases... + if (!strcasecmp("blake2", arg)) + i = opt_algo = ALGO_BLAKE2S; + else if (!strcasecmp("cryptonight-light", arg)) + i = opt_algo = ALGO_CRYPTOLIGHT; + else if (!strcasecmp("flax", arg)) + i = opt_algo = ALGO_C11; + else if (!strcasecmp("diamond", arg)) + i = opt_algo = ALGO_DMD_GR; + else if (!strcasecmp("droplp", arg)) + i = opt_algo = ALGO_DROP; + else if (!strcasecmp("jackpot", arg)) + i = opt_algo = ALGO_JHA; + else if (!strcasecmp("lyra2", arg)) + i = opt_algo = ALGO_LYRA2; + else if (!strcasecmp("lyra2v2", arg)) + i = opt_algo = ALGO_LYRA2REV2; + else if (!strcasecmp("lyra2rev3", arg)) + i = opt_algo = ALGO_LYRA2V3; + else if (!strcasecmp("monero", arg)) + i = opt_algo = ALGO_CRYPTONIGHT; + else if (!strcasecmp("phi", arg)) + i = opt_algo = ALGO_PHI1612; + else if (!strcasecmp("scryptjane", arg)) + i = opt_algo = ALGO_SCRYPTJANE; + else if (!strcasecmp("sibcoin", arg)) + i = opt_algo = ALGO_SIB; + else if (!strcasecmp("timetravel10", arg)) + i = opt_algo = ALGO_BITCORE; + else if (!strcasecmp("ziftr", arg)) + i = opt_algo = ALGO_ZR5; + else + applog(LOG_ERR, "Unknown algo parameter '%s'", arg); + } + if (i == ALGO_COUNT) { + show_usage_and_exit(1); + } + if (!opt_nfactor && opt_algo == ALGO_SCRYPT) + opt_nfactor = 9; + if (opt_algo == ALGO_SCRYPTJANE && opt_scrypt_n == 0) + opt_scrypt_n = 5; + break; + case 'b': + p = strstr(arg, ":"); + if (p) { + /* ip:port */ + if (p - arg > 0) { + free(opt_api_allow); + opt_api_allow = strdup(arg); + opt_api_allow[p - arg] = '\0'; + } + opt_api_listen = atoi(p + 1); + } + else if (arg && strstr(arg, ".")) { + /* ip only */ + free(opt_api_allow); + opt_api_allow = strdup(arg); + } + else if (arg) { + /* port or 0 to disable */ + opt_api_listen = atoi(arg); + } + break; + case 1030: /* --api-remote */ + opt_api_remote = 1; + break; + case 'n': + if (opt_algo == ALGO_NEOSCRYPT) { + v = atoi(arg); + /* Nfactor = lb(N) - 1; N = (1 << (Nfactor + 1)) */ + if ((v < 0) || (v > 30)) { + fprintf(stderr, "incorrect Nfactor %d\n", v); + show_usage_and_exit(1); + } + opt_nfactor = v; + } + break; + case 'B': + opt_background = true; + use_colors = false; + break; + case 'c': { + json_error_t err; + json_t *config; + if (arg && strstr(arg, "://")) { + config = json_load_url(arg, &err); + } else { + config = JSON_LOADF(arg, &err); + } + if (!json_is_object(config)) { + if (err.line < 0) + fprintf(stderr, "%s\n", err.text); + else + fprintf(stderr, "%s:%d: %s\n", + arg, err.line, err.text); + } else { + parse_config(config, arg); + json_decref(config); + } + break; + } + case 'C': + break; + case 'q': + opt_quiet = true; + break; + case 'D': + opt_debug = true; + break; + case 'p': + free(rpc_pass); + rpc_pass = strdup(arg); + strhide(arg); + break; + case 'P': + opt_protocol = true; + break; + case 'r': + v = atoi(arg); + if (v < -1 || v > 9999) /* sanity check */ + show_usage_and_exit(1); + opt_retries = v; + break; + case 'R': + v = atoi(arg); + if (v < 1 || v > 9999) /* sanity check */ + show_usage_and_exit(1); + opt_fail_pause = v; + break; + case 's': + v = atoi(arg); + if (v < 1 || v > 9999) /* sanity check */ + show_usage_and_exit(1); + opt_scantime = v; + break; + case 'T': + v = atoi(arg); + if (v < 1 || v > 99999) /* sanity check */ + show_usage_and_exit(1); + opt_timeout = v; + break; + case 't': + v = atoi(arg); + if (v < 0 || v > 9999) /* sanity check */ + show_usage_and_exit(1); + opt_n_threads = v; + break; + case 'u': + free(rpc_user); + rpc_user = strdup(arg); + break; + case 'o': { /* --url */ + char *ap, *hp; + ap = strstr(arg, "://"); + ap = ap ? ap + 3 : arg; + hp = strrchr(arg, '@'); + if (hp) { + *hp = '\0'; + p = strchr(ap, ':'); + if (p) { + free(rpc_userpass); + rpc_userpass = strdup(ap); + free(rpc_user); + rpc_user = (char*) calloc(p - ap + 1, 1); + strncpy(rpc_user, ap, p - ap); + free(rpc_pass); + rpc_pass = strdup(++p); + if (*p) *p++ = 'x'; + v = (int) strlen(hp + 1) + 1; + memmove(p + 1, hp + 1, v); + memset(p + v, 0, hp - p); + hp = p; + } else { + free(rpc_user); + rpc_user = strdup(ap); + } + *hp++ = '@'; + } else + hp = ap; + if (ap != arg) { + if (strncasecmp(arg, "http://", 7) && + strncasecmp(arg, "https://", 8) && + strncasecmp(arg, "stratum+tcp://", 14)) { + fprintf(stderr, "unknown protocol -- '%s'\n", arg); + show_usage_and_exit(1); + } + free(rpc_url); + rpc_url = strdup(arg); + strcpy(rpc_url + (ap - arg), hp); + short_url = &rpc_url[ap - arg]; + } else { + if (*hp == '\0' || *hp == '/') { + fprintf(stderr, "invalid URL -- '%s'\n", + arg); + show_usage_and_exit(1); + } + free(rpc_url); + rpc_url = (char*) malloc(strlen(hp) + 8); + sprintf(rpc_url, "http://%s", hp); + short_url = &rpc_url[sizeof("http://")-1]; + } + have_stratum = !opt_benchmark && !strncasecmp(rpc_url, "stratum", 7); + break; + } + case 'O': /* --userpass */ + p = strchr(arg, ':'); + if (!p) { + fprintf(stderr, "invalid username:password pair -- '%s'\n", arg); + show_usage_and_exit(1); + } + free(rpc_userpass); + rpc_userpass = strdup(arg); + free(rpc_user); + rpc_user = (char*) calloc(p - arg + 1, 1); + strncpy(rpc_user, arg, p - arg); + free(rpc_pass); + rpc_pass = strdup(++p); + strhide(p); + break; + case 'x': /* --proxy */ + if (!strncasecmp(arg, "socks4://", 9)) + opt_proxy_type = CURLPROXY_SOCKS4; + else if (!strncasecmp(arg, "socks5://", 9)) + opt_proxy_type = CURLPROXY_SOCKS5; #if LIBCURL_VERSION_NUM >= 0x071200 - else if (!strncasecmp(arg, "socks4a://", 10)) - opt_proxy_type = CURLPROXY_SOCKS4A; - else if (!strncasecmp(arg, "socks5h://", 10)) - opt_proxy_type = CURLPROXY_SOCKS5_HOSTNAME; + else if (!strncasecmp(arg, "socks4a://", 10)) + opt_proxy_type = CURLPROXY_SOCKS4A; + else if (!strncasecmp(arg, "socks5h://", 10)) + opt_proxy_type = CURLPROXY_SOCKS5_HOSTNAME; #endif - else - opt_proxy_type = CURLPROXY_HTTP; - free(opt_proxy); - opt_proxy = strdup(arg); - break; - case 1001: - free(opt_cert); - opt_cert = strdup(arg); - break; - case 1005: - opt_benchmark = true; - want_longpoll = false; - want_stratum = false; - have_stratum = false; - break; - case 1003: - want_longpoll = false; - break; - case 1007: - want_stratum = false; - break; - case 1009: - opt_redirect = false; - break; - case 'S': - use_syslog = true; - break; - case 'V': - show_version_and_exit(); - case 'h': - show_usage_and_exit(0); - default: - show_usage_and_exit(1); - } + else + opt_proxy_type = CURLPROXY_HTTP; + free(opt_proxy); + opt_proxy = strdup(arg); + break; + case 1001: + free(opt_cert); + opt_cert = strdup(arg); + break; + case 1002: + use_colors = false; + break; + case 1003: + want_longpoll = false; + break; + case 1005: + opt_benchmark = true; + want_longpoll = false; + want_stratum = false; + have_stratum = false; + break; + case 1006: + print_hash_tests(); + exit(0); + case 1007: + want_stratum = false; + opt_extranonce = false; + break; + case 1008: + opt_time_limit = atoi(arg); + break; + case 1009: + opt_redirect = false; + break; + case 1010: + allow_getwork = false; + break; + case 1011: + have_gbt = false; + break; + case 1012: + opt_extranonce = false; + break; + case 1013: + opt_showdiff = true; + break; + case 1014: + opt_showdiff = false; + break; + case 1016: /* --coinbase-addr */ + pk_script_size = address_to_script(pk_script, sizeof(pk_script), arg); + if (!pk_script_size) { + fprintf(stderr, "invalid address -- '%s'\n", arg); + show_usage_and_exit(1); + } + break; + case 1015: /* --coinbase-sig */ + if (strlen(arg) + 1 > sizeof(coinbase_sig)) { + fprintf(stderr, "coinbase signature too long\n"); + show_usage_and_exit(1); + } + strcpy(coinbase_sig, arg); + break; + case 'f': + d = atof(arg); + if (d == 0.) /* --diff-factor */ + show_usage_and_exit(1); + opt_diff_factor = d; + break; + case 'm': + d = atof(arg); + if (d == 0.) /* --diff-multiplier */ + show_usage_and_exit(1); + opt_diff_factor = 1.0/d; + break; + case 'S': + use_syslog = true; + use_colors = false; + break; + case 1019: // max-log-rate + opt_maxlograte = atoi(arg); + break; + case 1020: + p = strstr(arg, "0x"); + if (p) + ul = strtoul(p, NULL, 16); + else + ul = atol(arg); + if (ul > (1UL< 5) /* sanity check */ + show_usage_and_exit(1); + opt_priority = v; + break; + case 1060: // max-temp + d = atof(arg); + opt_max_temp = d; + break; + case 1061: // max-diff + d = atof(arg); + opt_max_diff = d; + break; + case 1062: // max-rate + d = atof(arg); + p = strstr(arg, "K"); + if (p) d *= 1e3; + p = strstr(arg, "M"); + if (p) d *= 1e6; + p = strstr(arg, "G"); + if (p) d *= 1e9; + opt_max_rate = d; + break; + case 1024: + opt_randomize = true; + break; + case 'V': + show_version_and_exit(); + case 'h': + show_usage_and_exit(0); + default: + show_usage_and_exit(1); + } } -static void parse_config(void) { - int i; - json_t *val; - - if (!json_is_object(opt_config)) - return; - - for (i = 0; i < ARRAY_SIZE(options); i++) { - if (!options[i].name) - break; - if (!strcmp(options[i].name, "config")) - continue; - - val = json_object_get(opt_config, options[i].name); - if (!val) - continue; - - if (options[i].has_arg && json_is_string(val)) { - char *s = strdup(json_string_value(val)); - if (!s) - break; - parse_arg(options[i].val, s); - free(s); - } else if (!options[i].has_arg && json_is_true(val)) - parse_arg(options[i].val, ""); - else - applog(LOG_ERR, "JSON option %s invalid", options[i].name); - } +void parse_config(json_t *config, char *ref) +{ + int i; + json_t *val; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (!options[i].name) + break; + + val = json_object_get(config, options[i].name); + if (!val) + continue; + if (options[i].has_arg && json_is_string(val)) { + char *s = strdup(json_string_value(val)); + if (!s) + break; + parse_arg(options[i].val, s); + free(s); + } + else if (options[i].has_arg && json_is_integer(val)) { + char buf[16]; + sprintf(buf, "%d", (int)json_integer_value(val)); + parse_arg(options[i].val, buf); + } + else if (options[i].has_arg && json_is_real(val)) { + char buf[16]; + sprintf(buf, "%f", json_real_value(val)); + parse_arg(options[i].val, buf); + } + else if (!options[i].has_arg) { + if (json_is_true(val)) + parse_arg(options[i].val, ""); + } + else + applog(LOG_ERR, "JSON option %s invalid", + options[i].name); + } } -static void parse_cmdline(int argc, char *argv[]) { - int key; +static void parse_cmdline(int argc, char *argv[]) +{ + int key; - while (1) { + while (1) { #if HAVE_GETOPT_LONG - key = getopt_long(argc, argv, short_options, options, NULL ); + key = getopt_long(argc, argv, short_options, options, NULL); #else - key = getopt(argc, argv, short_options); + key = getopt(argc, argv, short_options); #endif - if (key < 0) - break; - - parse_arg(key, optarg); - } - if (optind < argc) { - fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0], - argv[optind]); - show_usage_and_exit(1); - } - - parse_config(); + if (key < 0) + break; + + parse_arg(key, optarg); + } + if (optind < argc) { + fprintf(stderr, "%s: unsupported non-option argument -- '%s'\n", + argv[0], argv[optind]); + show_usage_and_exit(1); + } } #ifndef WIN32 -static void signal_handler(int sig) { - switch (sig) { - case SIGHUP: - applog(LOG_INFO, "SIGHUP received"); - break; - case SIGINT: - applog(LOG_INFO, "SIGINT received, exiting"); - exit(0); - break; - case SIGTERM: - applog(LOG_INFO, "SIGTERM received, exiting"); - exit(0); - break; - } +static void signal_handler(int sig) +{ + switch (sig) { + case SIGHUP: + applog(LOG_INFO, "SIGHUP received"); + break; + case SIGINT: + applog(LOG_INFO, "SIGINT received, exiting"); + proper_exit(0); + break; + case SIGTERM: + applog(LOG_INFO, "SIGTERM received, exiting"); + proper_exit(0); + break; + } +} +#else +BOOL WINAPI ConsoleHandler(DWORD dwType) +{ + switch (dwType) { + case CTRL_C_EVENT: + applog(LOG_INFO, "CTRL_C_EVENT received, exiting"); + proper_exit(0); + break; + case CTRL_BREAK_EVENT: + applog(LOG_INFO, "CTRL_BREAK_EVENT received, exiting"); + proper_exit(0); + break; + default: + return false; + } + return true; } #endif -static inline int cpuid(int code, uint32_t where[4]) { - asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)), - "=c"(*(where+2)),"=d"(*(where+3)):"a"(code)); - return (int)where[0]; +static int thread_create(struct thr_info *thr, void* func) +{ + int err = 0; + pthread_attr_init(&thr->attr); + err = pthread_create(&thr->pth, &thr->attr, func, thr); + pthread_attr_destroy(&thr->attr); + return err; } -static bool has_aes_ni() +static void show_credits() { - uint32_t cpu_info[4]; - cpuid(1, cpu_info); - return cpu_info[2] & (1 << 25); + printf("** " PACKAGE_NAME " " PACKAGE_VERSION " by tpruvot@github **\n"); + printf("BTC donation address: 1FhDPLPpw18X4srecguG3MxJYe4a1JsZnd (tpruvot)\n\n"); } +void get_defconfig_path(char *out, size_t bufsize, char *argv0); + int main(int argc, char *argv[]) { struct thr_info *thr; long flags; - int i; + int i, err; + + pthread_mutex_init(&applog_lock, NULL); + + show_credits(); rpc_user = strdup(""); rpc_pass = strdup(""); + opt_api_allow = strdup("127.0.0.1"); /* 0.0.0.0 for all ips */ + +#if defined(WIN32) + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + num_cpus = sysinfo.dwNumberOfProcessors; +#elif defined(_SC_NPROCESSORS_CONF) + num_cpus = sysconf(_SC_NPROCESSORS_CONF); +#elif defined(CTL_HW) && defined(HW_NCPU) + int req[] = { CTL_HW, HW_NCPU }; + size_t len = sizeof(num_cpus); + sysctl(req, 2, &num_cpus, &len, NULL, 0); +#else + num_cpus = 1; +#endif + if (num_cpus < 1) + num_cpus = 1; /* parse command line */ parse_cmdline(argc, argv); + if (!opt_benchmark && !rpc_url) { + // try default config file in binary folder + char defconfig[MAX_PATH] = { 0 }; + get_defconfig_path(defconfig, MAX_PATH, argv[0]); + if (strlen(defconfig)) { + if (opt_debug) + applog(LOG_DEBUG, "Using config %s", defconfig); + parse_arg('c', defconfig); + parse_cmdline(argc, argv); + } + } + + if (!opt_n_threads) + opt_n_threads = num_cpus; + if (!opt_n_threads) + opt_n_threads = 1; + if (opt_algo == ALGO_QUARK) { init_quarkhash_contexts(); - } else if (opt_algo == ALGO_BLAKE) { - init_blakehash_contexts(); - } else if(opt_algo == ALGO_CRYPTONIGHT) { + } else if(opt_algo == ALGO_CRYPTONIGHT || opt_algo == ALGO_CRYPTOLIGHT) { jsonrpc_2 = true; + opt_extranonce = false; aes_ni_supported = has_aes_ni(); - applog(LOG_INFO, "Using JSON-RPC 2.0"); - applog(LOG_INFO, "CPU Supports AES-NI: %s", aes_ni_supported ? "YES" : "NO"); + if (!opt_quiet) { + applog(LOG_INFO, "Using JSON-RPC 2.0"); + applog(LOG_INFO, "CPU Supports AES-NI: %s", aes_ni_supported ? "YES" : "NO"); + } + } else if(opt_algo == ALGO_DECRED || opt_algo == ALGO_SIA) { + have_gbt = false; } - if (!opt_benchmark && !rpc_url) { fprintf(stderr, "%s: no URL supplied\n", argv[0]); show_usage_and_exit(1); } if (!rpc_userpass) { - rpc_userpass = malloc(strlen(rpc_user) + strlen(rpc_pass) + 2); + rpc_userpass = (char*) malloc(strlen(rpc_user) + strlen(rpc_pass) + 2); if (!rpc_userpass) return 1; sprintf(rpc_userpass, "%s:%s", rpc_user, rpc_pass); } - pthread_mutex_init(&applog_lock, NULL ); - pthread_mutex_init(&stats_lock, NULL ); - pthread_mutex_init(&g_work_lock, NULL ); - pthread_mutex_init(&rpc2_job_lock, NULL ); - pthread_mutex_init(&stratum.sock_lock, NULL ); - pthread_mutex_init(&stratum.work_lock, NULL ); + pthread_mutex_init(&stats_lock, NULL); + pthread_mutex_init(&g_work_lock, NULL); + pthread_mutex_init(&rpc2_job_lock, NULL); + pthread_mutex_init(&rpc2_login_lock, NULL); + pthread_mutex_init(&stratum.sock_lock, NULL); + pthread_mutex_init(&stratum.work_lock, NULL); - flags = !opt_benchmark && strncmp(rpc_url, "https:", 6) ? - (CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL) : CURL_GLOBAL_ALL; + flags = !opt_benchmark && strncmp(rpc_url, "https:", 6) + ? (CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL) + : CURL_GLOBAL_ALL; if (curl_global_init(flags)) { applog(LOG_ERR, "CURL initialization failed"); return 1; @@ -1883,10 +3547,8 @@ int main(int argc, char *argv[]) { #ifndef WIN32 if (opt_background) { i = fork(); - if (i < 0) - exit(1); - if (i > 0) - exit(0); + if (i < 0) exit(1); + if (i > 0) exit(0); i = setsid(); if (i < 0) applog(LOG_ERR, "setsid() failed (errno = %d)", errno); @@ -1894,39 +3556,57 @@ int main(int argc, char *argv[]) { if (i < 0) applog(LOG_ERR, "chdir() failed (errno = %d)", errno); signal(SIGHUP, signal_handler); - signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); } -#endif - -#if defined(WIN32) - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - num_processors = sysinfo.dwNumberOfProcessors; -#elif defined(_SC_NPROCESSORS_CONF) - num_processors = sysconf(_SC_NPROCESSORS_CONF); -#elif defined(CTL_HW) && defined(HW_NCPU) - int req[] = {CTL_HW, HW_NCPU}; - size_t len = sizeof(num_processors); - sysctl(req, 2, &num_processors, &len, NULL, 0); + /* Always catch Ctrl+C */ + signal(SIGINT, signal_handler); #else - num_processors = 1; + SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE); + if (opt_background) { + HWND hcon = GetConsoleWindow(); + if (hcon) { + // this method also hide parent command line window + ShowWindow(hcon, SW_HIDE); + } else { + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + CloseHandle(h); + FreeConsole(); + } + } + if (opt_priority > 0) { + DWORD prio = NORMAL_PRIORITY_CLASS; + switch (opt_priority) { + case 1: + prio = BELOW_NORMAL_PRIORITY_CLASS; + break; + case 3: + prio = ABOVE_NORMAL_PRIORITY_CLASS; + break; + case 4: + prio = HIGH_PRIORITY_CLASS; + break; + case 5: + prio = REALTIME_PRIORITY_CLASS; + } + SetPriorityClass(GetCurrentProcess(), prio); + } #endif - if (num_processors < 1) - num_processors = 1; - if (!opt_n_threads) - opt_n_threads = num_processors - 1; + if (opt_affinity != -1) { + if (!opt_quiet) + applog(LOG_DEBUG, "Binding process to cpu mask %x", opt_affinity); + affine_to_cpu_mask(-1, (unsigned long)opt_affinity); + } #ifdef HAVE_SYSLOG_H if (use_syslog) openlog("cpuminer", LOG_PID, LOG_USER); #endif - work_restart = calloc(opt_n_threads, sizeof(*work_restart)); + work_restart = (struct work_restart*) calloc(opt_n_threads, sizeof(*work_restart)); if (!work_restart) return 1; - thr_info = calloc(opt_n_threads + 3, sizeof(*thr)); + thr_info = (struct thr_info*) calloc(opt_n_threads + 4, sizeof(*thr)); if (!thr_info) return 1; @@ -1942,12 +3622,16 @@ int main(int argc, char *argv[]) { if (!thr->q) return 1; + if (rpc_pass && rpc_user) + opt_stratum_stats = (strstr(rpc_pass, "stats") != NULL) || (strcmp(rpc_user, "benchmark") == 0); + /* start work I/O thread */ - if (pthread_create(&thr->pth, NULL, workio_thread, thr)) { - applog(LOG_ERR, "workio thread create failed"); + if (thread_create(thr, workio_thread)) { + applog(LOG_ERR, "work thread create failed"); return 1; } + /* ESET-NOD32 Detects these 2 thread_create... */ if (want_longpoll && !have_stratum) { /* init longpoll thread info */ longpoll_thr_id = opt_n_threads + 1; @@ -1958,8 +3642,9 @@ int main(int argc, char *argv[]) { return 1; /* start longpoll thread */ - if (unlikely(pthread_create(&thr->pth, NULL, longpoll_thread, thr))) { - applog(LOG_ERR, "longpoll thread create failed"); + err = thread_create(thr, longpoll_thread); + if (err) { + applog(LOG_ERR, "long poll thread create failed"); return 1; } } @@ -1973,15 +3658,30 @@ int main(int argc, char *argv[]) { return 1; /* start stratum thread */ - if (unlikely(pthread_create(&thr->pth, NULL, stratum_thread, thr))) { + err = thread_create(thr, stratum_thread); + if (err) { applog(LOG_ERR, "stratum thread create failed"); return 1; } - if (have_stratum) tq_push(thr_info[stratum_thr_id].q, strdup(rpc_url)); } + if (opt_api_listen) { + /* api thread */ + api_thr_id = opt_n_threads + 3; + thr = &thr_info[api_thr_id]; + thr->id = api_thr_id; + thr->q = tq_new(); + if (!thr->q) + return 1; + err = thread_create(thr, api_thread); + if (err) { + applog(LOG_ERR, "api thread create failed"); + return 1; + } + } + /* start mining threads */ for (i = 0; i < opt_n_threads; i++) { thr = &thr_info[i]; @@ -1991,19 +3691,22 @@ int main(int argc, char *argv[]) { if (!thr->q) return 1; - if (unlikely(pthread_create(&thr->pth, NULL, miner_thread, thr))) { + err = thread_create(thr, miner_thread); + if (err) { applog(LOG_ERR, "thread %d create failed", i); return 1; } } applog(LOG_INFO, "%d miner threads started, " - "using '%s' algorithm.", opt_n_threads, algo_names[opt_algo]); + "using '%s' algorithm.", + opt_n_threads, + algo_names[opt_algo]); /* main loop - simply wait for workio thread to exit */ - pthread_join(thr_info[work_thr_id].pth, NULL ); + pthread_join(thr_info[work_thr_id].pth, NULL); - applog(LOG_INFO, "workio thread dead, exiting."); + applog(LOG_WARNING, "workio thread dead, exiting."); return 0; } diff --git a/cpuminer-conf.json b/cpuminer-conf.json new file mode 100644 index 000000000..25b827cee --- /dev/null +++ b/cpuminer-conf.json @@ -0,0 +1,21 @@ +{ + "_comment1" : "Any long-format command line argument ", + "_comment2" : "may be used in this JSON configuration file", + + "api-bind" : "127.0.0.1:4048", + + "url" : "stratum+tcp://yiimp.ccminer.org:4252", + "user" : "benchmark", + "pass" : "d=0.024", + + "algo" : "decred", + "threads" : 0, + "cpu-priority" : 0, + "cpu-affinity" : -1, + + "benchmark" : false, + "debug" : false, + "protocol": false, + "show-diff": true, + "quiet" : false +} diff --git a/minerd.1 b/cpuminer.1 similarity index 78% rename from minerd.1 rename to cpuminer.1 index 489efb3d5..581be77fe 100644 --- a/minerd.1 +++ b/cpuminer.1 @@ -1,34 +1,35 @@ -.TH MINERD 1 "February 2014" "cpuminer 2.3.3" +.TH CPUMINER 1 "May 2014" "cpuminer 2.4" .SH NAME -minerd \- CPU miner for Bitcoin and Litecoin +cpuminer \- CPU miner for Bitcoin and Litecoin .SH SYNOPSIS -.B minerd +.B cpuminer [\fIOPTION\fR]... .SH DESCRIPTION -.B minerd +.B cpuminer is a multi-threaded CPU miner for Bitcoin, Litecoin and other cryptocurrencies. -It supports the getwork mining protocol as well as the Stratum mining protocol. +It supports the getwork and getblocktemplate (BIP 22) methods, +as well as the Stratum mining protocol. .PP -In its normal mode of operation, \fBminerd\fR connects to a mining server +In its normal mode of operation, \fBcpuminer\fR connects to a mining server (specified with the \fB\-o\fR option), receives work from it and starts hashing. As soon as a solution is found, it is submitted to the same mining server, which can accept or reject it. -When using the getwork protocol, \fBminerd\fR can take advantage -of the long polling extension, if the server supports it; +When using getwork or getblocktemplate, +\fBcpuminer\fR can take advantage of long polling, if the server supports it; in any case, fresh work is fetched as needed. When using the Stratum protocol this is not possible, and the server is responsible for sending fresh work at least every minute; if it fails to do so, -\fBminerd\fR may drop the connection and try reconnecting again. +\fBcpuminer\fR may drop the connection and try reconnecting again. .PP -By default, \fBminerd\fR writes all its messages to standard error. +By default, \fBcpuminer\fR writes all its messages to standard error. On systems that have a syslog, the \fB\-\-syslog\fR option can be used to write to it instead. .PP On start, the nice value of all miner threads is set to 19. On Linux, the scheduling policy is also changed to SCHED_IDLE, or to SCHED_BATCH if that fails. -On multiprocessor systems, \fBminerd\fR +On multiprocessor systems, \fBcpuminer\fR automatically sets the CPU affinity of miner threads if the number of threads is a multiple of the number of processors. .SH EXAMPLES @@ -37,7 +38,7 @@ at example.com on port 3333, authenticating as worker "foo" with password "bar": .PP .nf .RS -minerd \-o stratum+tcp://example.com:3333 \-O foo:bar +cpuminer \-o stratum+tcp://example.com:3333 \-O foo:bar .RE .fi .PP @@ -46,7 +47,8 @@ authenticating with username "rpcuser" and password "rpcpass": .PP .nf .RS -minerd \-a sha256d \-o http://localhost:18332 \-O rpcuser:rpcpass +cpuminer \-a sha256d \-o http://localhost:18332 \-O rpcuser:rpcpass \\ + \-\-coinbase\-addr=mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt .RE .fi .PP @@ -56,7 +58,7 @@ omitting the per-thread hashmeter output: .PP .nf .RS -minerd \-BSq \-o http://my.server:9327 +cpuminer \-BSq \-o http://my.server:9327 .RE .fi .SH OPTIONS @@ -87,6 +89,15 @@ Run in the background as a daemon. Set an SSL certificate to use with the mining server. Only supported when using the HTTPS protocol. .TP +\fB\-\-coinbase\-addr\fR=\fIADDRESS\fR +Set a payout address for solo mining. +This is only used in getblocktemplate mode, +and only if the server does not provide a coinbase transaction. +.TP +\fB\-\-coinbase\-sig\fR=\fITEXT\fR +Set a string to be included in the coinbase (if allowed by the server). +This is only used in getblocktemplate mode. +.TP \fB\-c\fR, \fB\-\-config\fR=\fIFILE\fR Load options from a configuration file. \fIFILE\fR must contain a JSON object @@ -109,6 +120,12 @@ Enable debug output. \fB\-h\fR, \fB\-\-help\fR Print a help message and exit. .TP +\fB\-\-no\-gbt\fR +Do not use the getblocktemplate RPC method. +.TP +\fB\-\-no\-getwork\fR +Do not use the getwork RPC method. +.TP \fB\-\-no\-longpoll\fR Do not use long polling. .TP @@ -124,6 +141,12 @@ Supported schemes are \fBhttp\fR, \fBhttps\fR and \fBstratum+tcp\fR. If no scheme is specified, http is assumed. Specifying a \fIPATH\fR is only supported for HTTP and HTTPS. Specifying credentials has the same effect as using the \fB\-O\fR option. + +By default, on HTTP and HTTPS, +the miner tries to use the getblocktemplate RPC method, +and falls back to using getwork if getblocktemplate is unavailable. +This behavior can be modified by using the \fB\-\-no\-gbt\fR +and \fB\-\-no\-getwork\fR options. .TP \fB\-O\fR, \fB\-\-userpass\fR=\fIUSERNAME\fR:\fIPASSWORD\fR Set the credentials to use for connecting to the mining server. @@ -195,7 +218,8 @@ Sets the proxy server to use if no protocol-specific proxy is set. Using an environment variable to set the proxy has the same effect as using the \fB\-x\fR option. .SH AUTHOR -Most of the code in the current version of minerd was written by -Pooler with contributions from others. +This variant is maintained by tpruvot@github. +Most of the code in the current version of cpuminer was written by +Pooler with contributions from others. The original minerd was written by Jeff Garzik . diff --git a/cpuminer.nsi b/cpuminer.nsi new file mode 100644 index 000000000..d522bcc81 --- /dev/null +++ b/cpuminer.nsi @@ -0,0 +1,363 @@ +; NSIS script (UTF-8) NSIS-3 Unicode +; Install + +; Unicode true +; SetCompressor lzma +RequestExecutionLevel Admin + +; -------------------- + +!include x64.nsh +!include FileFunc.nsh +!include WinMessages.nsh + +AllowRootDirInstall true + +; -------------------- +; LANG TABLES: 1 + +!define MINER_VERSION "1.1" +!define VERSION "${MINER_VERSION}.0.0" + +BrandingText "CPU Miner Install System" + +!define PROGRAM_NAME "CPU Miner" +!define PROGRAM_KEY "cpuminer" + +Name "cpuminer-multi v${MINER_VERSION}" +OutFile "${PROGRAM_KEY}-setup.exe" +Icon "res\setup.ico" +; Icon "res\${PROGRAM_KEY}.ico" +Caption "${PROGRAM_NAME}" + +VIProductVersion "${VERSION}" +VIAddVersionKey ProductName "${PROGRAM_NAME} - Setup" +VIAddVersionKey Comments "" +VIAddVersionKey CompanyName "Open Source" +VIAddVersionKey LegalCopyright "2015 - Open Source" +VIAddVersionKey FileDescription "${PROGRAM_NAME} - Setup" +VIAddVersionKey FileVersion "${MINER_VERSION}" +VIAddVersionKey ProductVersion "${MINER_VERSION}" +VIAddVersionKey InternalName "${PROGRAM_NAME}" +VIAddVersionKey LegalTrademarks "" +VIAddVersionKey OriginalFilename "${PROGRAM_KEY}.exe" + +!define NSIS_MAKENSIS64 +!ifdef NSIS_MAKENSIS64 + !define BITS 64 + InstallDir $PROGRAMFILES64\cpuminer-multi + !define RK_UNINSTALL "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_KEY}" +!else + !define BITS 32 + InstallDir $PROGRAMFILES32\cpuminer-multi + !define RK_UNINSTALL "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_KEY}" + ;!define RK_UNINSTALL "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_KEY}" +!endif + +# Test folders x86/x64 +# InstType "Custom" +# InstallDir $WINDIR\system32 + +; LANG: ${LANG_ENGLISH} +LangString LSTR_0 ${LANG_ENGLISH} "CPU Miner Install System" +LangString LSTR_3 ${LANG_ENGLISH} "Space available: " +LangString LSTR_4 ${LANG_ENGLISH} "Space required: " +LangString LSTR_5 ${LANG_ENGLISH} "Can't write: " +LangString LSTR_17 ${LANG_ENGLISH} "Error decompressing data! Corrupted installer?" +LangString LSTR_21 ${LANG_ENGLISH} "Extract: " +LangString LSTR_22 ${LANG_ENGLISH} "Extract: error writing to file " +LangString LSTR_25 ${LANG_ENGLISH} "Output folder: " +LangString LSTR_29 ${LANG_ENGLISH} "Skipped: " +LangString LSTR_30 ${LANG_ENGLISH} "Copy Details To Clipboard" +LangString LSTR_32 ${LANG_ENGLISH} "B" +LangString LSTR_33 ${LANG_ENGLISH} "K" +LangString LSTR_34 ${LANG_ENGLISH} "M" +LangString LSTR_35 ${LANG_ENGLISH} "G" +LangString LSTR_36 ${LANG_ENGLISH} "Choose Install Location" +LangString LSTR_37 ${LANG_ENGLISH} "Choose the folder in which to install ${PROGRAM_NAME}." +LangString LSTR_38 ${LANG_ENGLISH} "Installing" +LangString LSTR_39 ${LANG_ENGLISH} "Please wait while ${PROGRAM_NAME} is being installed." +LangString LSTR_40 ${LANG_ENGLISH} "Installation Complete" +LangString LSTR_41 ${LANG_ENGLISH} "Setup was completed successfully." +LangString LSTR_42 ${LANG_ENGLISH} "Installation Aborted" +LangString LSTR_43 ${LANG_ENGLISH} "Setup was not completed successfully." +LangString LSTR_44 ${LANG_ENGLISH} "MS Shell Dlg" +LangString LSTR_45 ${LANG_ENGLISH} "8" +LangString LSTR_46 ${LANG_ENGLISH} "Error opening file for writing: $\r$\n$\r$\n$0$\r$\n$\r$\nClick Abort to stop the installation,$\r$\nRetry to try again, or$\r$\nIgnore to skip this file." +LangString LSTR_48 ${LANG_ENGLISH} "Cancel" +LangString LSTR_49 ${LANG_ENGLISH} "Setup will install ${PROGRAM_NAME} in the following folder. To install in a different folder, click Browse and select another folder. $_CLICK" +LangString LSTR_50 ${LANG_ENGLISH} "Destination Folder" +LangString LSTR_51 ${LANG_ENGLISH} "B&rowse..." +LangString LSTR_52 ${LANG_ENGLISH} "Select the folder to install ${PROGRAM_NAME} in:" +LangString LSTR_53 ${LANG_ENGLISH} "< &Back" +LangString LSTR_54 ${LANG_ENGLISH} "&Install" +LangString LSTR_55 ${LANG_ENGLISH} "Click Install to start the installation." +LangString LSTR_56 ${LANG_ENGLISH} "Show &details" +LangString LSTR_57 ${LANG_ENGLISH} "Completed" +LangString LSTR_58 ${LANG_ENGLISH} "&Next >" +LangString LSTR_59 ${LANG_ENGLISH} "Click Next to continue." +LangString LSTR_60 ${LANG_ENGLISH} " " +LangString LSTR_61 ${LANG_ENGLISH} "&Close" + + +; -------------------- +; VARIABLES: + +Var _0_ +Var _1_ +Var _2_ +Var _3_ +Var _4_ +Var _5_ +Var _6_ + +Var DATADIR +Var REALINSTDIR + +; -------------------- +; PAGES: 3 + +; Page 0 +Page directory func_title_pre0 func_show0 func_leave0 /ENABLECANCEL +; DirVar $CMDLINE + DirText $(LSTR_49) $(LSTR_50) $(LSTR_51) $(LSTR_52) ; Setup will install ${PROGRAM_NAME} in the following folder.... + +; Page 1 +Page instfiles func_title_pre1 func_show1 func_leave1 + CompletedText $(LSTR_57) ; Completed + DetailsButtonText $(LSTR_56) ; Show &details + +/* +; Page 2 +Page COMPLETED +*/ + + +; -------------------- + +Function func_title_pre0 ; Page 0, Pre + SendMessage $_0_ ${WM_SETTEXT} 0 STR:$(LSTR_36) ; Choose Install Location + SendMessage $_2_ ${WM_SETTEXT} 0 STR:$(LSTR_37) ; Choose the folder in which to install ${PROGRAM_NAME}. +FunctionEnd + + +Function func_show0 ; Page 0, Show +; FindWindow $_12_ "#32770" "" $HWNDPARENT +; GetDlgItem $_13_ $_12_ 1006 +; GetDlgItem $_14_ $_12_ 1020 +; GetDlgItem $_15_ $_12_ 1019 +; GetDlgItem $_16_ $_12_ 1001 +; GetDlgItem $_17_ $_12_ 1023 +; GetDlgItem $_18_ $_12_ 1024 +FunctionEnd + + +Function func_leave0 ; Page 0, Leave +FunctionEnd + + +Function func_title_pre1 ; Page 1, Pre + SendMessage $_0_ ${WM_SETTEXT} 0 STR:$(LSTR_38) ; Installing + SendMessage $_2_ ${WM_SETTEXT} 0 STR:$(LSTR_39) ; Please wait while ${PROGRAM_NAME} is being installed. cpuminer-multi +FunctionEnd + + +Function func_show1 ; Page 1, Show +; FindWindow $_19_ "#32770" "" $HWNDPARENT +; GetDlgItem $_20_ $_19_ 1006 +; GetDlgItem $_21_ $_19_ 1004 +; GetDlgItem $_22_ $_19_ 1027 +; GetDlgItem $_23_ $_19_ 1016 +FunctionEnd + + +Function func_leave1 ; Page 1, Leave + IfAbort label_27 + SendMessage $_0_ ${WM_SETTEXT} 0 STR:$(LSTR_40) ; "Installation Complete" + SendMessage $_2_ ${WM_SETTEXT} 0 STR:$(LSTR_41) ; "Setup was completed successfully." + Goto label_29 +label_27: + SendMessage $_0_ ${WM_SETTEXT} 0 STR:$(LSTR_42) ; "Installation Aborted" + SendMessage $_2_ ${WM_SETTEXT} 0 STR:$(LSTR_43) ; "Setup was not completed successfully." +label_29: + IfAbort label_30 +label_30: +FunctionEnd + +Function .onInit + # `/SD IDYES' tells MessageBox to automatically choose IDYES if the installer is silent + # in this case, the installer can only be silent if the user used the /S switch or if + # you've uncommented line number 5 + # MessageBox MB_YESNO|MB_ICONQUESTION "Would you like the installer to be silent from now on?" \ + # /SD IDYES IDNO no IDYES yes + # yes: + # SetSilent silent + # Goto done + # no: + # SetSilent normal + + #SetSilent silent + + ReadRegStr $R0 HKLM ${RK_UNINSTALL} \ + "UninstallString" + StrCmp $R0 "" done + + DeleteRegKey HKLM ${RK_UNINSTALL} + ClearErrors + +done: + +FunctionEnd + + +Function .onGUIInit + GetDlgItem $_0_ $HWNDPARENT 1037 + CreateFont $_1_ $(LSTR_44) $(LSTR_45) 700 ; "MS Shell Dlg" 8 + SendMessage $_0_ ${WM_SETFONT} $_1_ 0 + GetDlgItem $_2_ $HWNDPARENT 1038 + SetCtlColors $_0_ "" 0xFFFFFF + SetCtlColors $_2_ "" 0xFFFFFF + GetDlgItem $_3_ $HWNDPARENT 1034 + SetCtlColors $_3_ "" 0xFFFFFF + GetDlgItem $_4_ $HWNDPARENT 1039 + SetCtlColors $_4_ "" 0xFFFFFF + GetDlgItem $_6_ $HWNDPARENT 1028 + SetCtlColors $_6_ /BRANDING "" + GetDlgItem $_5_ $HWNDPARENT 1256 + SetCtlColors $_5_ /BRANDING "" + SendMessage $_5_ ${WM_SETTEXT} 0 "STR:$(LSTR_0) " ; "CPU Miner Install System" +; GetDlgItem $_7_ $HWNDPARENT 1035 +; GetDlgItem $_8_ $HWNDPARENT 1045 +; GetDlgItem $_9_ $HWNDPARENT 1 +; GetDlgItem $_10_ $HWNDPARENT 2 +; GetDlgItem $_11_ $HWNDPARENT 3 +FunctionEnd + + +Function .onUserAbort +FunctionEnd + + +Section + + StrCpy $DATADIR "$APPDATA\${PROGRAM_KEY}" + StrCpy $REALINSTDIR "$INSTDIR" + ${If} ${RunningX64} + ${DisableX64FSRedirection} + ; StrCmp $INSTDIR "$WINDIR\system32" 0 +2 + ; StrCpy $INSTDIR "$WINDIR\sysnative" + SetRegView 64 + ${Else} + SetRegView 32 + ${Endif} + + SetOutPath "$INSTDIR" + + # call UserInfo plugin to get user info. The plugin puts the result in the stack + UserInfo::getAccountType + # pop the result from the stack into $0 + Pop $0 + + # If match, jump 3 lines down. + StrCmp $0 "Admin" +3 + MessageBox MB_OK "Installer requires admin rights: $0" + Return + + SetOverwrite on + File cpuminer-gw64.exe + File cpuminer-x64.exe + File cpuminer-conf.json + File /oname=LICENSE.txt LICENSE + File /oname=README.txt README.md + + SetOverwrite off + AllowSkipFiles on + File x64\Release\msvcr120.dll + + # Create the uninstaller + CreateDirectory "$DATADIR" + File "/oname=$DATADIR\cpuminer-conf.json" cpuminer-conf.json + WriteUninstaller "$DATADIR\cpuminer-uninst.exe" + + # Shortcuts (program + uninstaller) + CreateDirectory "$SMPROGRAMS\${PROGRAM_NAME}" + CreateShortCut /NoWorkingDir "$SMPROGRAMS\${PROGRAM_NAME}\${PROGRAM_NAME}.lnk" "$REALINSTDIR\cpuminer-gw64.exe" + CreateShortCut /NoWorkingDir "$SMPROGRAMS\${PROGRAM_NAME}\Config.lnk" "$SYSDIR\notepad.exe" "$DATADIR\cpuminer-conf.json" + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Uninstall.lnk" "$DATADIR\cpuminer-uninst.exe" + CreateShortCut /NoWorkingDir "$SMPROGRAMS\${PROGRAM_NAME}\${PROGRAM_NAME}-bg.lnk" "$REALINSTDIR\cpuminer-gw64.exe" "-q -B" "" "" SW_SHOWMINIMIZED + + WriteRegStr HKLM ${RK_UNINSTALL} \ + "DisplayName" "${PROGRAM_NAME}" + + WriteRegStr HKLM ${RK_UNINSTALL} \ + "DisplayVersion" "${MINER_VERSION}" + + WriteRegStr HKLM ${RK_UNINSTALL} \ + "Publisher" "Open Source" + + WriteRegStr HKLM ${RK_UNINSTALL} \ + "DisplayIcon" "$REALINSTDIR\cpuminer-x64.exe" + + WriteRegStr HKLM ${RK_UNINSTALL} \ + "InstallLocation" "$REALINSTDIR" + + WriteRegStr HKLM ${RK_UNINSTALL} \ + "UninstallString" "$\"$DATADIR\cpuminer-uninst.exe$\"" + + ${GetSize} "$INSTDIR" "/M=cpuminer* /S=0K /G=0" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${RK_UNINSTALL}" \ + "EstimatedSize" "$0" + + # Add application to Windows Firewall exception list (to check) + ;liteFirewall::AddRule "$REALINSTDIR\cpuminer-gw64.exe" "CPU Miner (MinGW64)" + ;liteFirewall::AddRule "$REALINSTDIR\cpuminer-x64.exe" "CPU Miner (x64)" + +SectionEnd + + +Section "uninstall" + + StrCpy $DATADIR "$APPDATA\${PROGRAM_KEY}" + ${If} ${RunningX64} + ;StrCmp $INSTDIR "$WINDIR\system32" 0 +2 + ;StrCpy $INSTDIR "$WINDIR\sysnative" + ${DisableX64FSRedirection} + SetRegView 64 + ${Else} + SetRegView 32 + ${Endif} + + ReadRegStr $INSTDIR HKLM ${RK_UNINSTALL} "InstallLocation" + StrCpy $REALINSTDIR "$INSTDIR" + + Delete "$INSTDIR\cpuminer-conf.json" + Delete "$INSTDIR\cpuminer-gw64.exe" + Delete "$INSTDIR\cpuminer-x64.exe" + Delete "$INSTDIR\LICENSE.txt" + Delete "$INSTDIR\README.txt" + + StrCmp $REALINSTDIR "$WINDIR/system32" +2 + Delete "$INSTDIR\msvcr120.dll" + RMDir "$INSTDIR" + + Delete "$DATADIR\cpuminer-uninst.exe" + RMDir "$DATADIR" + + ; Delete "$DATADIR\cpuminer-conf.json" + ; RMDir "$DATADIR" + + # second, remove the link from the start menu + Delete "$SMPROGRAMS\${PROGRAM_NAME}\${PROGRAM_NAME}.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\${PROGRAM_NAME}-bg.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Config.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Uninstall.lnk" + RMDir "$SMPROGRAMS\${PROGRAM_NAME}" + + DeleteRegKey HKLM ${RK_UNINSTALL} + + # Remove application from Windows Firewall exception list + ;liteFirewall::RemoveRule "$REALINSTDIR\cpuminer-gw64.exe" "CPU Miner (MinGW64)" + ;liteFirewall::RemoveRule "$REALINSTDIR\cpuminer-x64.exe" "CPU Miner (x64)" + +SectionEnd diff --git a/cpuminer.sln b/cpuminer.sln new file mode 100644 index 000000000..be2d7d281 --- /dev/null +++ b/cpuminer.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpuminer", "cpuminer.vcxproj", "{36DC07F9-A4A6-4877-A146-1B960083CF6F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|Win32 = Debug|Win32 + Release|x64 = Release|x64 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Debug|x64.ActiveCfg = Debug|x64 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Debug|Win32.ActiveCfg = Debug|Win32 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Debug|x64.Build.0 = Debug|x64 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Debug|Win32.Build.0 = Debug|Win32 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Release|x64.ActiveCfg = Release|x64 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Release|x64.Build.0 = Release|x64 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Release|Win32.ActiveCfg = Release|Win32 + {36DC07F9-A4A6-4877-A146-1B960083CF6F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/cpuminer.vcxproj b/cpuminer.vcxproj new file mode 100644 index 000000000..fbf220ed2 --- /dev/null +++ b/cpuminer.vcxproj @@ -0,0 +1,416 @@ + + + + + Release + Win32 + + + Debug + Win32 + + + Release + x64 + + + Debug + x64 + + + + {36DC07F9-A4A6-4877-A146-1B960083CF6F} + cpuminer + + + + Application + false + MultiByte + v120 + false + + + Application + true + MultiByte + v120 + false + + + Application + false + true + MultiByte + v120 + false + + + Application + true + MultiByte + v120 + false + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Level3 + Disabled + StreamingSIMDExtensions2 + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;CURL_STATICLIB;USE_AVX;USE_AVX2;USE_XOP;SCRYPT_KECCAK512;SCRYPT_CHACHA;SCRYPT_CHOOSE_COMPILETIME;%(PreprocessorDefinitions) + .;compat;compat\curl-for-windows\curl\include;compat\jansson;compat\getopt;compat\pthreads;compat\curl-for-windows\openssl\openssl\include;compat\curl-for-windows\zlib;%(AdditionalIncludeDirectories) + true + + + true + Console + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;pthreadVC2.lib;libcurl.x86.lib;openssl.x86.lib;zlib.x86.lib;ws2_32.lib;Wldap32.lib;%(AdditionalDependencies) + compat\pthreads\x86;compat\curl-for-windows\out\x86\Release\lib;%(AdditionalLibraryDirectories) + /NODEFAULTLIB:LIBCMT %(AdditionalOptions) + true + + + + + Level3 + Disabled + AdvancedVectorExtensions + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;CURL_STATICLIB;USE_AVX;USE_AVX2;USE_XOP;SCRYPT_KECCAK512;SCRYPT_CHACHA;SCRYPT_CHOOSE_COMPILETIME;%(PreprocessorDefinitions) + .;compat;compat\curl-for-windows\curl\include;compat\jansson;compat\getopt;compat\pthreads;compat\curl-for-windows\openssl\openssl\include;compat\curl-for-windows\zlib;%(AdditionalIncludeDirectories) + true + + + true + Console + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;pthreadVC2.lib;libcurl.x64.lib;openssl.x64.lib;zlib.x64.lib;ws2_32.lib;Wldap32.lib;%(AdditionalDependencies) + compat\pthreads\x64;compat\curl-for-windows\out\x64\Release\lib;%(AdditionalLibraryDirectories) + /NODEFAULTLIB:LIBCMT %(AdditionalOptions) + true + + + + + Level3 + MaxSpeed + MultiThreaded + Speed + StreamingSIMDExtensions2 + false + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;CURL_STATICLIB;USE_AVX;USE_AVX2;USE_XOP;SCRYPT_KECCAK512;SCRYPT_CHACHA;SCRYPT_CHOOSE_COMPILETIME;%(PreprocessorDefinitions) + .;compat;compat\curl-for-windows\curl\include;compat\jansson;compat\getopt;compat\pthreads;compat\curl-for-windows\openssl\openssl\include;compat\curl-for-windows\zlib;%(AdditionalIncludeDirectories) + true + SyncCThrow + + + false + true + true + Console + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;pthreadVC2.lib;libcurl.x86.lib;openssl.x86.lib;zlib.x86.lib;ws2_32.lib;Wldap32.lib;%(AdditionalDependencies) + compat\pthreads\x86;compat\curl-for-windows\out\x86\Release\lib;%(AdditionalLibraryDirectories) + /NODEFAULTLIB:LIBCMT %(AdditionalOptions) + false + false + + + + + Level3 + MaxSpeed + MultiThreaded + Speed + false + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;CURL_STATICLIB;SCRYPT_KECCAK512;SCRYPT_CHACHA;SCRYPT_CHOOSE_COMPILETIME;%(PreprocessorDefinitions) + .;compat;compat\curl-for-windows\curl\include;compat\jansson;compat\getopt;compat\pthreads;compat\curl-for-windows\openssl\openssl\include;compat\curl-for-windows\zlib;%(AdditionalIncludeDirectories) + true + + + false + true + true + Console + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;pthreadVC2.lib;libcurl.x64.lib;openssl.x64.lib;zlib.x64.lib;ws2_32.lib;Wldap32.lib;%(AdditionalDependencies) + compat\pthreads\x64;compat\curl-for-windows\out\x64\Release\lib;%(AdditionalLibraryDirectories) + /NODEFAULTLIB:LIBCMT %(AdditionalOptions) + false + + + + + + + + + + + + + + + + + + false + Full + + + + + + + + + + + + + + + + + + + Full + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Full + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + + + + + + + + diff --git a/cpuminer.vcxproj.filters b/cpuminer.vcxproj.filters new file mode 100644 index 000000000..f7c3c1327 --- /dev/null +++ b/cpuminer.vcxproj.filters @@ -0,0 +1,656 @@ + + + + + + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + compat + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + compat + + + compat + + + jansson + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + arch\x86 + + + arch\x64 + + + arch\x86 + + + arch\x64 + + + arch\x64 + + + arch\x86 + + + + + jansson + + + jansson + + + jansson + + + jansson + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + algo + + + yescrypt + + + yescrypt + + + yescrypt + + + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + sph + + + compat + + + compat + + + compat + + + compat + + + compat + + + compat + + + compat + + + compat + + + headers + + + headers + + + headers + + + jansson + + + jansson + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + crypto + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + scrypt-jane + + + crypto + + + res + + + yescrypt + + + yescrypt + + + yescrypt + + + yescrypt + + + + + {822b216c-102a-48ca-b62b-7689df410249} + + + {f5e8fc70-27e7-41ab-a14d-2b0462350980} + + + {343fa430-44d1-4ff7-b15d-8915052fe036} + + + {88b3057f-0bb6-49d4-98a4-551c8bd8ce0d} + + + {d17f8918-3371-4acb-ba63-06be828562a1} + + + {04c96afe-01af-4f5c-9ee7-219481033018} + + + {774a7c76-80c0-4a15-983a-022d17e08420} + + + {e2f9ccb4-db0b-4e4f-9cfd-935e8e0ebb78} + + + {5a05483f-0f3f-43fe-bfd1-a14519e30e4d} + + + {5ed226e8-1512-481d-a88d-18644da87dcd} + + + {34f266e4-b48f-4721-ac34-474b65726498} + + + {5969f6d8-98c0-49c9-8e4c-51c54b5f0e16} + + + {678c0f76-3cd5-418b-bc6b-84a10d81f789} + + + + + algo + + + algo + + + + + res + + + + + res + + + diff --git a/crypto/aesb-x86-impl.c b/crypto/aesb-x86-impl.c deleted file mode 100644 index ddd0ee8a9..000000000 --- a/crypto/aesb-x86-impl.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "int-util.h" -#include - -uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { - // multiplier = ab = a * 2^32 + b - // multiplicand = cd = c * 2^32 + d - // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d - uint64_t a = hi_dword(multiplier); - uint64_t b = lo_dword(multiplier); - uint64_t c = hi_dword(multiplicand); - uint64_t d = lo_dword(multiplicand); - - uint64_t ac = a * c; - uint64_t ad = a * d; - uint64_t bc = b * c; - uint64_t bd = b * d; - - uint64_t adbc = ad + bc; - uint64_t adbc_carry = adbc < ad ? 1 : 0; - - // multiplier * multiplicand = product_hi * 2^64 + product_lo - uint64_t product_lo = bd + (adbc << 32); - uint64_t product_lo_carry = product_lo < bd ? 1 : 0; - *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; - - return product_lo; -} diff --git a/crypto/blake2b.c b/crypto/blake2b.c new file mode 100644 index 000000000..ccb76c662 --- /dev/null +++ b/crypto/blake2b.c @@ -0,0 +1,196 @@ +/* + * Copyright 2009 Colin Percival, 2014 savale + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include + +#include +#include "blake2b.h" + +// Cyclic right rotation. + +#ifndef ROTR64 +#define ROTR64(x, y) (((x) >> (y)) ^ ((x) << (64 - (y)))) +#endif + +// Little-endian byte access. + +#define B2B_GET64(p) \ + (((uint64_t) ((uint8_t *) (p))[0]) ^ \ + (((uint64_t) ((uint8_t *) (p))[1]) << 8) ^ \ + (((uint64_t) ((uint8_t *) (p))[2]) << 16) ^ \ + (((uint64_t) ((uint8_t *) (p))[3]) << 24) ^ \ + (((uint64_t) ((uint8_t *) (p))[4]) << 32) ^ \ + (((uint64_t) ((uint8_t *) (p))[5]) << 40) ^ \ + (((uint64_t) ((uint8_t *) (p))[6]) << 48) ^ \ + (((uint64_t) ((uint8_t *) (p))[7]) << 56)) + +// G Mixing function. + +#define B2B_G(a, b, c, d, x, y) { \ + v[a] = v[a] + v[b] + x; \ + v[d] = ROTR64(v[d] ^ v[a], 32); \ + v[c] = v[c] + v[d]; \ + v[b] = ROTR64(v[b] ^ v[c], 24); \ + v[a] = v[a] + v[b] + y; \ + v[d] = ROTR64(v[d] ^ v[a], 16); \ + v[c] = v[c] + v[d]; \ + v[b] = ROTR64(v[b] ^ v[c], 63); } + +// Initialization Vector. + +static const uint64_t blake2b_iv[8] = { + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, + 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 +}; + +// Compression function. "last" flag indicates last block. + +static void blake2b_compress(blake2b_ctx *ctx, int last) +{ + const uint8_t sigma[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } + }; + int i; + uint64_t v[16], m[16]; + + for (i = 0; i < 8; i++) { // init work variables + v[i] = ctx->h[i]; + v[i + 8] = blake2b_iv[i]; + } + + v[12] ^= ctx->t[0]; // low 64 bits of offset + v[13] ^= ctx->t[1]; // high 64 bits + if (last) // last block flag set ? + v[14] = ~v[14]; + + for (i = 0; i < 16; i++) // get little-endian words + m[i] = B2B_GET64(&ctx->b[8 * i]); + + for (i = 0; i < 12; i++) { // twelve rounds + B2B_G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]); + B2B_G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]); + B2B_G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]); + B2B_G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]); + B2B_G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]); + B2B_G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]); + B2B_G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]); + B2B_G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]); + } + + for( i = 0; i < 8; ++i ) + ctx->h[i] ^= v[i] ^ v[i + 8]; +} + +// Initialize the hashing context "ctx" with optional key "key". +// 1 <= outlen <= 64 gives the digest size in bytes. +// Secret key (also <= 64 bytes) is optional (keylen = 0). + +int blake2b_init(blake2b_ctx *ctx, size_t outlen, + const void *key, size_t keylen) // (keylen=0: no key) +{ + size_t i; + + if (outlen == 0 || outlen > 64 || keylen > 64) + return -1; // illegal parameters + + for (i = 0; i < 8; i++) // state, "param block" + ctx->h[i] = blake2b_iv[i]; + ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; + + ctx->t[0] = 0; // input count low word + ctx->t[1] = 0; // input count high word + ctx->c = 0; // pointer within buffer + ctx->outlen = outlen; + + for (i = keylen; i < 128; i++) // zero input block + ctx->b[i] = 0; + if (keylen > 0) { + blake2b_update(ctx, key, keylen); + ctx->c = 128; // at the end + } + + return 0; +} + +// Add "inlen" bytes from "in" into the hash. + +void blake2b_update(blake2b_ctx *ctx, + const void *in, size_t inlen) // data bytes +{ + size_t i; + + for (i = 0; i < inlen; i++) { + if (ctx->c == 128) { // buffer full ? + ctx->t[0] += ctx->c; // add counters + if (ctx->t[0] < ctx->c) // carry overflow ? + ctx->t[1]++; // high word + blake2b_compress(ctx, 0); // compress (not last) + ctx->c = 0; // counter to zero + } + ctx->b[ctx->c++] = ((const uint8_t *) in)[i]; + } +} + +// Generate the message digest (size given in init). +// Result placed in "out". + +void blake2b_final(blake2b_ctx *ctx, void *out) +{ + size_t i; + + ctx->t[0] += ctx->c; // mark last block offset + if (ctx->t[0] < ctx->c) // carry overflow + ctx->t[1]++; // high word + + while (ctx->c < 128) // fill up with zeros + ctx->b[ctx->c++] = 0; + blake2b_compress(ctx, 1); // final block flag = 1 + + // little endian convert and store + for (i = 0; i < ctx->outlen; i++) { + ((uint8_t *) out)[i] = + (ctx->h[i >> 3] >> (8 * (i & 7))) & 0xFF; + } +} + diff --git a/crypto/blake2b.h b/crypto/blake2b.h new file mode 100644 index 000000000..f8652c180 --- /dev/null +++ b/crypto/blake2b.h @@ -0,0 +1,41 @@ +#pragma once +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +#if defined(_MSC_VER) +#include +#define inline __inline +#define ALIGN(x) __declspec(align(x)) +#else +#define ALIGN(x) __attribute__((aligned(x))) +#endif + +#if defined(_MSC_VER) || defined(__x86_64__) || defined(__x86__) +#define NATIVE_LITTLE_ENDIAN +#endif + +// state context +ALIGN(64) typedef struct { + uint8_t b[128]; // input buffer + uint64_t h[8]; // chained state + uint64_t t[2]; // total number of bytes + size_t c; // pointer for b[] + size_t outlen; // digest size +} blake2b_ctx; + +#if defined(__cplusplus) +extern "C" { +#endif + +int blake2b_init(blake2b_ctx *ctx, size_t outlen, const void *key, size_t keylen); +void blake2b_update(blake2b_ctx *ctx, const void *in, size_t inlen); +void blake2b_final(blake2b_ctx *ctx, void *out); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/crypto/blake2s.c b/crypto/blake2s.c new file mode 100644 index 000000000..0914b5aa7 --- /dev/null +++ b/crypto/blake2s.c @@ -0,0 +1,378 @@ +/** + * BLAKE2 reference source code package - reference C implementations + * + * Written in 2012 by Samuel Neves + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along with + * this software. If not, see . + */ + +#include +#include +#include + +#include "sha3/sph_types.h" +#include "crypto/blake2s.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static inline int blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = ~0U; + return 0; +} + +static inline int blake2s_clear_lastnode( blake2s_state *S ) +{ + S->f[1] = 0U; + return 0; +} + +/* Some helper functions, not necessarily useful */ +static inline int blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = ~0U; + return 0; +} + +static inline int blake2s_clear_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_clear_lastnode( S ); + + S->f[0] = 0U; + return 0; +} + +static inline int blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); + return 0; +} + +// Parameter-related functions +static inline int blake2s_param_set_digest_length( blake2s_param *P, const uint8_t digest_length ) +{ + P->digest_length = digest_length; + return 0; +} + +static inline int blake2s_param_set_fanout( blake2s_param *P, const uint8_t fanout ) +{ + P->fanout = fanout; + return 0; +} + +static inline int blake2s_param_set_max_depth( blake2s_param *P, const uint8_t depth ) +{ + P->depth = depth; + return 0; +} + +static inline int blake2s_param_set_leaf_length( blake2s_param *P, const uint32_t leaf_length ) +{ + store32( &P->leaf_length, leaf_length ); + return 0; +} + +static inline int blake2s_param_set_node_offset( blake2s_param *P, const uint64_t node_offset ) +{ + store48( P->node_offset, node_offset ); + return 0; +} + +static inline int blake2s_param_set_node_depth( blake2s_param *P, const uint8_t node_depth ) +{ + P->node_depth = node_depth; + return 0; +} + +static inline int blake2s_param_set_inner_length( blake2s_param *P, const uint8_t inner_length ) +{ + P->inner_length = inner_length; + return 0; +} + +static inline int blake2s_param_set_salt( blake2s_param *P, const uint8_t salt[BLAKE2S_SALTBYTES] ) +{ + memcpy( P->salt, salt, BLAKE2S_SALTBYTES ); + return 0; +} + +static inline int blake2s_param_set_personal( blake2s_param *P, const uint8_t personal[BLAKE2S_PERSONALBYTES] ) +{ + memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES ); + return 0; +} + +static inline int blake2s_init0( blake2s_state *S ) +{ + memset( S, 0, sizeof( blake2s_state ) ); + + for( int i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; + + return 0; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + blake2s_init0( S ); + uint32_t *p = ( uint32_t * )( P ); + + /* IV XOR ParamBlock */ + for( size_t i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i] ); + + return 0; +} + + +// Sequential blake2s initialization +int blake2s_init( blake2s_state *S, const uint8_t outlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store48( &P->node_offset, 0 ); + P->node_depth = 0; + P->inner_length = 0; + // memset(P->reserved, 0, sizeof(P->reserved) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store48( &P->node_offset, 0 ); + P->node_depth = 0; + P->inner_length = 0; + // memset(P->reserved, 0, sizeof(P->reserved) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +int blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16]; + uint32_t v[16]; + + for( size_t i = 0; i < 16; ++i ) + m[i] = load32( block + i * sizeof( m[i] ) ); + + for( size_t i = 0; i < 8; ++i ) + v[i] = S->h[i]; + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = SPH_ROTR32(d ^ a, 16); \ + c = c + d; \ + b = SPH_ROTR32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = SPH_ROTR32(d ^ a, 8); \ + c = c + d; \ + b = SPH_ROTR32(b ^ c, 7); \ + } while(0) +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( size_t i = 0; i < 8; ++i ) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + +#undef G +#undef ROUND + return 0; +} + + +int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen ) +{ + while( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = 2 * BLAKE2S_BLOCKBYTES - left; + + if( inlen > fill ) + { + memcpy( S->buf + left, in, fill ); // Fill buffer + S->buflen += fill; + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); // Compress + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left + S->buflen -= BLAKE2S_BLOCKBYTES; + in += fill; + inlen -= fill; + } + else // inlen <= fill + { + memcpy(S->buf + left, in, (size_t) inlen); + S->buflen += (size_t) inlen; // Be lazy, do not compress + in += inlen; + inlen -= inlen; + } + } + + return 0; +} + +int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES]; + + if( S->buflen > BLAKE2S_BLOCKBYTES ) + { + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); + S->buflen -= BLAKE2S_BLOCKBYTES; + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen ); + } + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( int i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, outlen ); + return 0; +} + +int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ) +{ + blake2s_state S; + + /* Verify parameters */ + if ( NULL == in ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key ) keylen = 0; /* Fail here instead if keylen != 0 and key == NULL? */ + + if( keylen > 0 ) + { + if( blake2s_init_key( &S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2s_init( &S, outlen ) < 0 ) return -1; + } + + blake2s_update( &S, ( uint8_t * )in, inlen ); + blake2s_final( &S, out, outlen ); + return 0; +} + +#if defined(BLAKE2S_SELFTEST) +#include +#include "blake2-kat.h" /* test data not included */ +int main( int argc, char **argv ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[KAT_LENGTH]; + + for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + puts( "error" ); + return -1; + } + } + + puts( "ok" ); + return 0; +} +#endif diff --git a/crypto/blake2s.h b/crypto/blake2s.h new file mode 100644 index 000000000..23f8d909c --- /dev/null +++ b/crypto/blake2s.h @@ -0,0 +1,154 @@ +/** + * BLAKE2 reference source code package - reference C implementations + * + * Written in 2012 by Samuel Neves + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along with + * this software. If not, see . + */ +#pragma once +#ifndef __BLAKE2_H__ +#define __BLAKE2_H__ + +#include +#include + +#if defined(_MSC_VER) +#include +#define inline __inline +#define ALIGN(x) __declspec(align(x)) +#else +#define ALIGN(x) __attribute__((aligned(x))) +#endif + +#if defined(_MSC_VER) || defined(__x86_64__) || defined(__x86__) +#define NATIVE_LITTLE_ENDIAN +#endif + +/* blake2-impl.h */ + +static inline uint32_t load32(const void *src) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + return *(uint32_t *)(src); +#else + const uint8_t *p = (uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static inline void store32(void *dst, uint32_t w) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + *(uint32_t *)(dst) = w; +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static inline uint64_t load48(const void *src) +{ + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + return w; +} + +static inline void store48(void *dst, uint64_t w) +{ + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; w >>= 8; + *p++ = (uint8_t)w; +} + +/* prevents compiler optimizing out memset() */ +static inline void secure_zero_memory(void *v, size_t n) +{ + volatile uint8_t *p = ( volatile uint8_t * )v; + + while( n-- ) *p++ = 0; +} + +/* blake2.h */ + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +#pragma pack(push, 1) +typedef struct __blake2s_param +{ + uint8_t digest_length; // 1 + uint8_t key_length; // 2 + uint8_t fanout; // 3 + uint8_t depth; // 4 + uint32_t leaf_length; // 8 + uint8_t node_offset[6];// 14 + uint8_t node_depth; // 15 + uint8_t inner_length; // 16 + // uint8_t reserved[0]; + uint8_t salt[BLAKE2S_SALTBYTES]; // 24 + uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32 +} blake2s_param; + +ALIGN( 64 ) typedef struct __blake2s_state +{ + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[2 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + uint8_t last_node; +} blake2s_state; +#pragma pack(pop) + +#if defined(__cplusplus) +extern "C" { +#endif + + int blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLOCKBYTES] ); + + // Streaming API + int blake2s_init( blake2s_state *S, const uint8_t outlen ); + int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen ); + int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen ); + + // Simple API + int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + + // Direct Hash Mining Helpers + #define blake2s_salt32(out, in, inlen, key32) blake2s(out, in, key32, 32, inlen, 32) /* neoscrypt */ + #define blake2s_simple(out, in, inlen) blake2s(out, in, NULL, 32, inlen, 0) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/crypto/c_blake256.c b/crypto/c_blake256.c index 0b484b945..e91df3790 100644 --- a/crypto/c_blake256.c +++ b/crypto/c_blake256.c @@ -147,8 +147,8 @@ void blake256_update(state *S, const uint8_t *data, uint64_t datalen) { } if (datalen > 0) { - memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); - S->buflen = (left << 3) + datalen; + memcpy((void *) (S->buf + left), (void *) data, (size_t) (datalen >> 3)); + S->buflen = (left << 3) + (int) datalen; } else { S->buflen = 0; } diff --git a/crypto/c_jh.c b/crypto/c_jh.c index 728f3bbee..43eaffce6 100644 --- a/crypto/c_jh.c +++ b/crypto/c_jh.c @@ -260,17 +260,16 @@ static HashReturn Update(hashState *state, const BitSequence *data, DataLength d /*There is data in the buffer, but the incoming data is insufficient for a full block*/ if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) { - if ( (databitlen & 7) == 0 ) { - memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ; - } - else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ; + if ( (databitlen & 7) == 0 ) + memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, (size_t) (64-(state->datasize_in_buffer >> 3)) ); + else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, (size_t) (64 - (state->datasize_in_buffer >> 3) + 1) ); state->datasize_in_buffer += databitlen; databitlen = 0; } /*There is data in the buffer, and the incoming data is sufficient for a full block*/ if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) { - memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ; + memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, (size_t) (64-(state->datasize_in_buffer >> 3)) ); index = 64-(state->datasize_in_buffer >> 3); databitlen = databitlen - (512 - state->datasize_in_buffer); F8(state); diff --git a/crypto/hash-ops.h b/crypto/hash-ops.h index b0a26b87e..20fa67ea0 100644 --- a/crypto/hash-ops.h +++ b/crypto/hash-ops.h @@ -13,6 +13,7 @@ #include "int-util.h" +#if 0 static inline void *padd(void *p, size_t i) { return (char *) p + i; } @@ -23,11 +24,12 @@ static inline const void *cpadd(const void *p, size_t i) { static inline void place_length(uint8_t *buffer, size_t bufsize, size_t length) { if (sizeof(size_t) == 4) { - *(uint32_t *) padd(buffer, bufsize - 4) = swap32be(length); + *(uint32_t*) padd(buffer, bufsize - 4) = swap32be(length); } else { - *(uint64_t *) padd(buffer, bufsize - 8) = swap64be(length); + *(uint64_t*) padd(buffer, bufsize - 8) = swap64be(length); } } +#endif #pragma pack(push, 1) union hash_state { @@ -37,7 +39,7 @@ union hash_state { #pragma pack(pop) void hash_permutation(union hash_state *state); -void hash_process(union hash_state *state, const uint8_t *buf, size_t count); +void hash_process(union hash_state *state, const uint8_t *buf, int count); #endif @@ -46,7 +48,7 @@ enum { HASH_DATA_AREA = 136 }; -void cn_fast_hash(const void *data, size_t length, char *hash); +void cn_fast_hash(const void *data, int len, char *hash); void cn_slow_hash(const void *data, size_t length, char *hash); void hash_extra_blake(const void *data, size_t length, char *hash); diff --git a/crypto/hash.c b/crypto/hash.c index f3a16f0c1..d9418ed82 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -13,12 +13,12 @@ void hash_permutation(union hash_state *state) { keccakf((uint64_t*)state, 24); } -void hash_process(union hash_state *state, const uint8_t *buf, size_t count) { +void hash_process(union hash_state *state, const uint8_t *buf, int count) { keccak1600(buf, count, (uint8_t*)state); } -void cn_fast_hash(const void *data, size_t length, char *hash) { +void cn_fast_hash(const void *data, int len, char *hash) { union hash_state state; - hash_process(&state, data, length); + hash_process(&state, data, len); memcpy(hash, &state, HASH_SIZE); } diff --git a/crypto/int-util.h b/crypto/int-util.h index c50ed7c66..93368bb22 100644 --- a/crypto/int-util.h +++ b/crypto/int-util.h @@ -3,18 +3,32 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once +#ifndef INT_UTILS_H_ +#define INT_UTILS_H_ #include #include #include #include +#ifndef _MSC_VER #include +#else +#define inline __inline +#endif + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 0x1234 +#define BIG_ENDIAN 0x4321 +#endif -#if defined(_MSC_VER) +#if !defined(BYTE_ORDER) && (defined(__LITTLE_ENDIAN__) || defined(__arm__) || defined(WIN32)) +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(WIN32) #include static inline uint32_t rol32(uint32_t x, int r) { - static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers"); return _rotl(x, r); } @@ -42,8 +56,6 @@ static inline uint64_t lo_dword(uint64_t val) { return val & 0xFFFFFFFF; } -extern uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi); - static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { dividend |= ((uint64_t)*remainder) << 32; *remainder = dividend % divisor; @@ -179,3 +191,5 @@ static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not e #define memcpy_swap64be memcpy_ident64 #define memcpy_swap64le memcpy_swap64 #endif + +#endif /* INT_UTILS_H_ */ diff --git a/crypto/oaes_lib.c b/crypto/oaes_lib.c index 27be98113..4cc7ae3bc 100644 --- a/crypto/oaes_lib.c +++ b/crypto/oaes_lib.c @@ -28,14 +28,56 @@ * --------------------------------------------------------------------------- */ static const char _NR[] = { - 0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20, - 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 }; + 0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20, + 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 +}; + +#include +#define NO_OLDNAMES /* timeb is still defined in mingw */ #include "miner.h" #include -#include -#include +#include + +// Only used by ftime, which was removed from POSIX 2008. +struct timeb { + time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +#ifdef _MSC_VER +struct timezone { + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; +#endif + +// This was removed from POSIX 2008. +static int ftime(struct timeb* tb) { + struct timeval tv; + struct timezone tz; + + if (gettimeofday(&tv, &tz) < 0) + return -1; + + tb->time = tv.tv_sec; + tb->millitm = (unsigned short) ((tv.tv_usec + 500) / 1000); + + if (tb->millitm == 1000) { + ++tb->time; + tb->millitm = 0; + } + + tb->timezone = tz.tz_minuteswest; + tb->dstflag = tz.tz_dsttime; + + return 0; +} + + #if !((defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__APPLE__)) #include #endif @@ -45,6 +87,7 @@ static const char _NR[] = { #ifdef WIN32 #include +#define getpid _getpid #else #include #include @@ -483,7 +526,7 @@ static uint32_t oaes_get_seed(void) _test = (char *) calloc( sizeof( char ), timer.millitm ); _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm + - (uintptr_t) ( _test + timer.millitm ) + getpid(); + (uint32_t) ( _test + timer.millitm ) + getpid(); if( _test ) free( _test ); @@ -655,7 +698,7 @@ OAES_RET oaes_key_export( OAES_CTX * ctx, // header memcpy( data, oaes_header, OAES_BLOCK_SIZE ); data[5] = 0x01; - data[7] = _ctx->key->data_len; + data[7] = (uint8_t) _ctx->key->data_len; memcpy( data + OAES_BLOCK_SIZE, _ctx->key->data, _ctx->key->data_len ); return OAES_RET_SUCCESS; @@ -1216,7 +1259,7 @@ OAES_RET oaes_encrypt( OAES_CTX * ctx, // insert pad for( _j = 0; _j < OAES_BLOCK_SIZE - _block_size; _j++ ) - _block[ _block_size + _j ] = _j + 1; + _block[_block_size + _j] = (uint8_t)_j + 1; // CBC if( _ctx->options & OAES_OPTION_CBC ) diff --git a/elist.h b/elist.h index b2e8263dc..d4c85dc61 100644 --- a/elist.h +++ b/elist.h @@ -30,14 +30,14 @@ struct list_head { * This is only for internal list manipulation where we know * the prev/next entries already! */ -static inline void __list_add(struct list_head *new, +static inline void __list_add(struct list_head *nlh, struct list_head *prev, struct list_head *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = nlh; + nlh->next = next; + nlh->prev = prev; + prev->next = nlh; } /** @@ -48,9 +48,9 @@ static inline void __list_add(struct list_head *new, * Insert a new entry after the specified head. * This is good for implementing stacks. */ -static inline void list_add(struct list_head *new, struct list_head *head) +static inline void list_add(struct list_head *nlh, struct list_head *head) { - __list_add(new, head, head->next); + __list_add(nlh, head, head->next); } /** @@ -61,9 +61,9 @@ static inline void list_add(struct list_head *new, struct list_head *head) * Insert a new entry before the specified head. * This is useful for implementing queues. */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) +static inline void list_add_tail(struct list_head *nlh, struct list_head *head) { - __list_add(new, head->prev, head); + __list_add(nlh, head->prev, head); } /* @@ -87,8 +87,8 @@ static inline void __list_del(struct list_head *prev, struct list_head *next) static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); - entry->next = (void *) 0; - entry->prev = (void *) 0; + entry->next = NULL; + entry->prev = NULL; } /** @@ -215,11 +215,12 @@ static inline void list_splice_init(struct list_head *list, * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. + * @type: the type of the struct. */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ +#define list_for_each_entry(pos, head, member, type) \ + for (pos = list_entry((head)->next, type, member); \ &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) + pos = list_entry(pos->member.next, type, member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry @@ -227,12 +228,13 @@ static inline void list_splice_init(struct list_head *list, * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. + * @type: the type of the struct. */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ +#define list_for_each_entry_safe(pos, n, head, member, type) \ + for (pos = list_entry((head)->next, type, member), \ + n = list_entry(pos->member.next, type, member); \ &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) + pos = n, n = list_entry(n->member.next, type, member)) /** * list_for_each_entry_continue - iterate over list of given type @@ -240,12 +242,13 @@ static inline void list_splice_init(struct list_head *list, * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. + * @type: the type of the struct. */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ +#define list_for_each_entry_continue(pos, head, member, type) \ + for (pos = list_entry(pos->member.next, type, member), \ prefetch(pos->member.next); \ &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ + pos = list_entry(pos->member.next, type, member), \ prefetch(pos->member.next)) #endif diff --git a/example-cfg.json b/example-cfg.json deleted file mode 100644 index 228a66d55..000000000 --- a/example-cfg.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_comment1" : "Any long-format command line argument ", - "_comment2" : "may be used in this JSON configuration file", - - "url" : "http://127.0.0.1:9332/", - "user" : "rpcuser", - "pass" : "rpcpass", - - "algo" : "scrypt", - "threads" : "4", - - "quiet" : true -} diff --git a/heavy.c b/heavy.c deleted file mode 100644 index 1907528f2..000000000 --- a/heavy.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include - -#include "miner.h" -#include "sha3/sph_hefty1.h" -#include "sha3/sph_keccak.h" -#include "sha3/sph_blake.h" -#include "sha3/sph_groestl.h" - -/* Combines top 64-bits from each hash into a single hash */ -static void combine_hashes(uint32_t *out, uint32_t *hash1, uint32_t *hash2, uint32_t *hash3, uint32_t *hash4) -{ - uint32_t *hash[4] = { hash1, hash2, hash3, hash4 }; - - /* Transpose first 64 bits of each hash into out */ - memset(out, 0, 32); - int bits = 0; - for (unsigned int i = 7; i >= 6; i--) { - for (uint32_t mask = 0x80000000; mask; mask >>= 1) { - for (unsigned int k = 0; k < 4; k++) { - out[(255 - bits)/32] <<= 1; - if ((hash[k][i] & mask) != 0) - out[(255 - bits)/32] |= 1; - bits++; - } - } - } -} - - - -void heavycoin_hash(unsigned char* output, const unsigned char* input, int len) -{ - unsigned char hash1[32]; - HEFTY1(input, len, hash1); - - /* HEFTY1 is new, so take an extra security measure to eliminate - * the possiblity of collisions: - * - * Hash(x) = SHA256(x + HEFTY1(x)) - * - * N.B. '+' is concatenation. - */ - unsigned char hash2[32];; - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, input, len); - SHA256_Update(&ctx, hash1, sizeof(hash1)); - SHA256_Final(hash2, &ctx); - - /* Additional security: Do not rely on a single cryptographic hash - * function. Instead, combine the outputs of 4 of the most secure - * cryptographic hash functions-- SHA256, KECCAK512, GROESTL512 - * and BLAKE512. - */ - - uint32_t hash3[16]; - sph_keccak512_context keccakCtx; - sph_keccak512_init(&keccakCtx); - sph_keccak512(&keccakCtx, input, len); - sph_keccak512(&keccakCtx, hash1, sizeof(hash1)); - sph_keccak512_close(&keccakCtx, (void *)&hash3); - - uint32_t hash4[16]; - sph_groestl512_context groestlCtx; - sph_groestl512_init(&groestlCtx); - sph_groestl512(&groestlCtx, input, len); - sph_groestl512(&groestlCtx, hash1, sizeof(hash1)); - sph_groestl512_close(&groestlCtx, (void *)&hash4); - - uint32_t hash5[16]; - sph_blake512_context blakeCtx; - sph_blake512_init(&blakeCtx); - sph_blake512(&blakeCtx, input, len); - sph_blake512(&blakeCtx, (unsigned char *)&hash1, sizeof(hash1)); - sph_blake512_close(&blakeCtx, (void *)&hash5); - - uint32_t *final = (uint32_t *)output; - combine_hashes(final, (uint32_t *)hash2, hash3, hash4, hash5); -} - -int scanhash_heavy(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t hash[8]; - uint32_t start_nonce = pdata[19]; - - do { - heavycoin_hash((unsigned char *)hash, (unsigned char *)pdata, 80); - - if (hash[7] <= ptarget[7]) { - if (fulltest(hash, ptarget)) { - *hashes_done = pdata[19] - start_nonce; - return 1; - break; - } - } - pdata[19]++; - } while (pdata[19] < max_nonce && !work_restart[thr_id].restart); - *hashes_done = pdata[19] - start_nonce; - return 0; -} \ No newline at end of file diff --git a/ink.c b/ink.c deleted file mode 100644 index 9080ad6ba..000000000 --- a/ink.c +++ /dev/null @@ -1,145 +0,0 @@ -#include "cpuminer-config.h" -#include "miner.h" - -#include -#include - -#include "sha3/sph_shavite.h" - -static void inkhash(void *state, const void *input) -{ - sph_shavite512_context ctx_shavite; - uint32_t hash[16]; - - sph_shavite512_init(&ctx_shavite); - sph_shavite512 (&ctx_shavite, (const void*) input, 80); - sph_shavite512_close(&ctx_shavite, (void*) hash); - - sph_shavite512_init(&ctx_shavite); - sph_shavite512(&ctx_shavite, (const void*) hash, 64); - sph_shavite512_close(&ctx_shavite, (void*) hash); - - memcpy(state, hash, 32); - -/* - int ii; - printf("result: "); - for (ii=0; ii < 32; ii++) - { - printf ("%.2x",((uint8_t*)state)[ii]); - }; - printf ("\n"); -*/ -} - -int scanhash_ink(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t n = pdata[19] - 1; - const uint32_t first_nonce = pdata[19]; - const uint32_t Htarg = ptarget[7]; - - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - - //char testdata[] = {"\x70\x00\x00\x00\x5d\x38\x5b\xa1\x14\xd0\x79\x97\x0b\x29\xa9\x41\x8f\xd0\x54\x9e\x7d\x68\xa9\x5c\x7f\x16\x86\x21\xa3\x14\x20\x10\x00\x00\x00\x00\x57\x85\x86\xd1\x49\xfd\x07\xb2\x2f\x3a\x8a\x34\x7c\x51\x6d\xe7\x05\x2f\x03\x4d\x2b\x76\xff\x68\xe0\xd6\xec\xff\x9b\x77\xa4\x54\x89\xe3\xfd\x51\x17\x32\x01\x1d\xf0\x73\x10\x00"}; - - //we need bigendian data... - //lessons learned: do NOT endianchange directly in pdata, this will all proof-of-works be considered as stale from minerd.... - int kk=0; - for (; kk < 32; kk++) - { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; - -// if (opt_debug) -// { -// applog(LOG_DEBUG, "Thr: %02d, firstN: %08x, maxN: %08x, ToDo: %d", thr_id, first_nonce, max_nonce, max_nonce-first_nonce); -// } - - /* I'm to lazy to put the loop in an inline function... so dirty copy'n'paste.... */ - /* i know that i could set a variable, but i don't know how the compiler will optimize it, not that then the cpu needs to load the value *everytime* in a register */ - if (ptarget[7]==0) { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - inkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFFFF)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - inkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFFF0)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - inkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFF00)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - inkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFF000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else if (ptarget[7]<=0xFFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - inkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFF0000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - inkhash(hash64, &endiandata); - if (fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - - - *hashes_done = n - first_nonce + 1; - pdata[19] = n; - return 0; -} \ No newline at end of file diff --git a/keccak.c b/keccak.c deleted file mode 100644 index 24e187c01..000000000 --- a/keccak.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "cpuminer-config.h" -#include "miner.h" - -#include -#include - -#include "sha3/sph_keccak.h" - -static void keccakhash(void *state, const void *input) -{ - sph_keccak256_context ctx_keccak; - uint32_t hash[32]; - - sph_keccak256_init(&ctx_keccak); - sph_keccak256 (&ctx_keccak,input, 80); - sph_keccak256_close(&ctx_keccak, hash); - - memcpy(state, hash, 32); -} - -int scanhash_keccak(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t n = pdata[19] - 1; - const uint32_t first_nonce = pdata[19]; - const uint32_t Htarg = ptarget[7]; - - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - - int kk=0; - for (; kk < 32; kk++) - { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; - - do { - - pdata[19] = ++n; - be32enc(&endiandata[19], n); - keccakhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFF00)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - *hashes_done = n - first_nonce + 1; - pdata[19] = n; - return 0; -} \ No newline at end of file diff --git a/lyra2/Lyra2.c b/lyra2/Lyra2.c new file mode 100644 index 000000000..a2016be8f --- /dev/null +++ b/lyra2/Lyra2.c @@ -0,0 +1,386 @@ +/** + * Implementation of the Lyra2 Password Hashing Scheme (PHS). + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#include "Lyra2.h" +#include "Sponge.h" + +/** + * Executes Lyra2 based on the G function from Blake2b. This version supports salts and passwords + * whose combined length is smaller than the size of the memory matrix, (i.e., (nRows x nCols x b) bits, + * where "b" is the underlying sponge's bitrate). In this implementation, the "basil" is composed by all + * integer parameters (treated as type "unsigned int") in the order they are provided, plus the value + * of nCols, (i.e., basil = kLen || pwdlen || saltlen || timeCost || nRows || nCols). + * + * @param K The derived key to be output by the algorithm + * @param kLen Desired key length + * @param pwd User password + * @param pwdlen Password length + * @param salt Salt + * @param saltlen Salt length + * @param timeCost Parameter to determine the processing time (T) + * @param nRows Number or rows of the memory matrix (R) + * @param nCols Number of columns of the memory matrix (C) + * + * @return 0 if the key is generated correctly; -1 if there is an error (usually due to lack of memory for allocation) + */ +int LYRA2(void *K, int64_t kLen, const void *pwd, int32_t pwdlen, const void *salt, int32_t saltlen, int64_t timeCost, const int16_t nRows, const int16_t nCols) +{ + //============================= Basic variables ============================// + int64_t row = 2; //index of row to be processed + int64_t prev = 1; //index of prev (last row ever computed/modified) + int64_t rowa = 0; //index of row* (a previous row, deterministically picked during Setup and randomly picked while Wandering) + int64_t tau; //Time Loop iterator + int64_t step = 1; //Visitation step (used during Setup and Wandering phases) + int64_t window = 2; //Visitation window (used to define which rows can be revisited during Setup) + int64_t gap = 1; //Modifier to the step, assuming the values 1 or -1 + int64_t i; //auxiliary iteration counter + int64_t v64; // 64bit var for memcpy + //==========================================================================/ + + //========== Initializing the Memory Matrix and pointers to it =============// + //Tries to allocate enough space for the whole memory matrix + + const int64_t ROW_LEN_INT64 = BLOCK_LEN_INT64 * nCols; + const int64_t ROW_LEN_BYTES = ROW_LEN_INT64 * 8; + // for Lyra2REv2, nCols = 4, v1 was using 8 + const int64_t BLOCK_LEN = (nCols == 4) ? BLOCK_LEN_BLAKE2_SAFE_INT64 : BLOCK_LEN_BLAKE2_SAFE_BYTES; + + i = (int64_t)ROW_LEN_BYTES * nRows; + uint64_t *wholeMatrix = malloc(i); + if (wholeMatrix == NULL) { + return -1; + } + memset(wholeMatrix, 0, i); + + //Allocates pointers to each row of the matrix + uint64_t **memMatrix = malloc(sizeof(uint64_t*) * nRows); + if (memMatrix == NULL) { + return -1; + } + //Places the pointers in the correct positions + uint64_t *ptrWord = wholeMatrix; + for (i = 0; i < nRows; i++) { + memMatrix[i] = ptrWord; + ptrWord += ROW_LEN_INT64; + } + //==========================================================================/ + + //============= Getting the password + salt + basil padded with 10*1 ===============// + //OBS.:The memory matrix will temporarily hold the password: not for saving memory, + //but this ensures that the password copied locally will be overwritten as soon as possible + + //First, we clean enough blocks for the password, salt, basil and padding + int64_t nBlocksInput = ((saltlen + pwdlen + 6 * sizeof(uint64_t)) / BLOCK_LEN_BLAKE2_SAFE_BYTES) + 1; + + byte *ptrByte = (byte*) wholeMatrix; + + //Prepends the password + memcpy(ptrByte, pwd, pwdlen); + ptrByte += pwdlen; + + //Concatenates the salt + memcpy(ptrByte, salt, saltlen); + ptrByte += saltlen; + + memset(ptrByte, 0, nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - (saltlen + pwdlen)); + + //Concatenates the basil: every integer passed as parameter, in the order they are provided by the interface + memcpy(ptrByte, &kLen, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = pwdlen; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = saltlen; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = timeCost; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = nRows; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = nCols; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + + //Now comes the padding + *ptrByte = 0x80; //first byte of padding: right after the password + ptrByte = (byte*) wholeMatrix; //resets the pointer to the start of the memory matrix + ptrByte += nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - 1; //sets the pointer to the correct position: end of incomplete block + *ptrByte ^= 0x01; //last byte of padding: at the end of the last incomplete block + //==========================================================================/ + + //======================= Initializing the Sponge State ====================// + //Sponge state: 16 uint64_t, BLOCK_LEN_INT64 words of them for the bitrate (b) and the remainder for the capacity (c) + uint64_t state[16]; + initState(state); + //==========================================================================/ + + //================================ Setup Phase =============================// + //Absorbing salt, password and basil: this is the only place in which the block length is hard-coded to 512 bits + ptrWord = wholeMatrix; + for (i = 0; i < nBlocksInput; i++) { + absorbBlockBlake2Safe(state, ptrWord); //absorbs each block of pad(pwd || salt || basil) + ptrWord += BLOCK_LEN; //goes to next block of pad(pwd || salt || basil) + } + + //Initializes M[0] and M[1] + reducedSqueezeRow0(state, memMatrix[0], nCols); //The locally copied password is most likely overwritten here + + reducedDuplexRow1(state, memMatrix[0], memMatrix[1], nCols); + + do { + //M[row] = rand; //M[row*] = M[row*] XOR rotW(rand) + + reducedDuplexRowSetup(state, memMatrix[prev], memMatrix[rowa], memMatrix[row], nCols); + + //updates the value of row* (deterministically picked during Setup)) + rowa = (rowa + step) & (window - 1); + //update prev: it now points to the last row ever computed + prev = row; + //updates row: goes to the next row to be computed + row++; + + //Checks if all rows in the window where visited. + if (rowa == 0) { + step = window + gap; //changes the step: approximately doubles its value + window *= 2; //doubles the size of the re-visitation window + gap = -gap; //inverts the modifier to the step + } + + } while (row < nRows); + //==========================================================================/ + + //============================ Wandering Phase =============================// + row = 0; //Resets the visitation to the first row of the memory matrix + for (tau = 1; tau <= timeCost; tau++) { + //Step is approximately half the number of all rows of the memory matrix for an odd tau; otherwise, it is -1 + step = (tau % 2 == 0) ? -1 : nRows / 2 - 1; + do { + //Selects a pseudorandom index row* + //------------------------------------------------------------------------------------------ + rowa = state[0] & (unsigned int)(nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + //rowa = state[0] % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + //Performs a reduced-round duplexing operation over M[row*] XOR M[prev], updating both M[row*] and M[row] + reducedDuplexRow(state, memMatrix[prev], memMatrix[rowa], memMatrix[row], nCols); + + //update prev: it now points to the last row ever computed + prev = row; + + //updates row: goes to the next row to be computed + //------------------------------------------------------------------------------------------ + row = (row + step) & (unsigned int)(nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + //row = (row + step) % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + } while (row != 0); + } + + //============================ Wrap-up Phase ===============================// + //Absorbs the last block of the memory matrix + absorbBlock(state, memMatrix[rowa]); + + //Squeezes the key + squeeze(state, K, (unsigned int) kLen); + + //========================= Freeing the memory =============================// + free(memMatrix); + free(wholeMatrix); + + return 0; +} + +int LYRA2_3(void *K, int64_t kLen, const void *pwd, int32_t pwdlen, const void *salt, int32_t saltlen, int64_t timeCost, const int16_t nRows, const int16_t nCols) +{ + //============================= Basic variables ============================// + int64_t row = 2; //index of row to be processed + int64_t prev = 1; //index of prev (last row ever computed/modified) + int64_t rowa = 0; //index of row* (a previous row, deterministically picked during Setup and randomly picked while Wandering) + int64_t tau; //Time Loop iterator + int64_t step = 1; //Visitation step (used during Setup and Wandering phases) + int64_t window = 2; //Visitation window (used to define which rows can be revisited during Setup) + int64_t gap = 1; //Modifier to the step, assuming the values 1 or -1 + int64_t i; //auxiliary iteration counter + int64_t v64; // 64bit var for memcpy + uint64_t instance = 0; + //==========================================================================/ + + //========== Initializing the Memory Matrix and pointers to it =============// + //Tries to allocate enough space for the whole memory matrix + + const int64_t ROW_LEN_INT64 = BLOCK_LEN_INT64 * nCols; + const int64_t ROW_LEN_BYTES = ROW_LEN_INT64 * 8; + const int64_t BLOCK_LEN = BLOCK_LEN_BLAKE2_SAFE_INT64; + + size_t sz = (size_t)ROW_LEN_BYTES * nRows; + uint64_t *wholeMatrix = malloc(sz); + if (wholeMatrix == NULL) { + return -1; + } + memset(wholeMatrix, 0, sz); + + //Allocates pointers to each row of the matrix + uint64_t **memMatrix = malloc(sizeof(uint64_t*) * nRows); + if (memMatrix == NULL) { + return -1; + } + //Places the pointers in the correct positions + uint64_t *ptrWord = wholeMatrix; + for (i = 0; i < nRows; i++) { + memMatrix[i] = ptrWord; + ptrWord += ROW_LEN_INT64; + } + //==========================================================================/ + + //============= Getting the password + salt + basil padded with 10*1 ===============// + //OBS.:The memory matrix will temporarily hold the password: not for saving memory, + //but this ensures that the password copied locally will be overwritten as soon as possible + + //First, we clean enough blocks for the password, salt, basil and padding + int64_t nBlocksInput = ((saltlen + pwdlen + 6 * sizeof(uint64_t)) / BLOCK_LEN_BLAKE2_SAFE_BYTES) + 1; + + byte *ptrByte = (byte*) wholeMatrix; + + //Prepends the password + memcpy(ptrByte, pwd, pwdlen); + ptrByte += pwdlen; + + //Concatenates the salt + memcpy(ptrByte, salt, saltlen); + ptrByte += saltlen; + + memset(ptrByte, 0, (size_t) (nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - (saltlen + pwdlen))); + + //Concatenates the basil: every integer passed as parameter, in the order they are provided by the interface + memcpy(ptrByte, &kLen, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = pwdlen; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = saltlen; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = timeCost; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = nRows; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + v64 = nCols; + memcpy(ptrByte, &v64, sizeof(int64_t)); + ptrByte += sizeof(uint64_t); + + //Now comes the padding + *ptrByte = 0x80; //first byte of padding: right after the password + ptrByte = (byte*) wholeMatrix; //resets the pointer to the start of the memory matrix + ptrByte += nBlocksInput * BLOCK_LEN_BLAKE2_SAFE_BYTES - 1; //sets the pointer to the correct position: end of incomplete block + *ptrByte ^= 0x01; //last byte of padding: at the end of the last incomplete block + //==========================================================================/ + + //======================= Initializing the Sponge State ====================// + //Sponge state: 16 uint64_t, BLOCK_LEN_INT64 words of them for the bitrate (b) and the remainder for the capacity (c) + uint64_t state[16]; + initState(state); + //==========================================================================/ + + //================================ Setup Phase =============================// + //Absorbing salt, password and basil: this is the only place in which the block length is hard-coded to 512 bits + ptrWord = wholeMatrix; + for (i = 0; i < nBlocksInput; i++) { + absorbBlockBlake2Safe(state, ptrWord); //absorbs each block of pad(pwd || salt || basil) + ptrWord += BLOCK_LEN; //goes to next block of pad(pwd || salt || basil) + } + + //Initializes M[0] and M[1] + reducedSqueezeRow0(state, memMatrix[0], nCols); //The locally copied password is most likely overwritten here + + reducedDuplexRow1(state, memMatrix[0], memMatrix[1], nCols); + + do { + //M[row] = rand; //M[row*] = M[row*] XOR rotW(rand) + + reducedDuplexRowSetup(state, memMatrix[prev], memMatrix[rowa], memMatrix[row], nCols); + + //updates the value of row* (deterministically picked during Setup)) + rowa = (rowa + step) & (window - 1); + //update prev: it now points to the last row ever computed + prev = row; + //updates row: goes to the next row to be computed + row++; + + //Checks if all rows in the window where visited. + if (rowa == 0) { + step = window + gap; //changes the step: approximately doubles its value + window *= 2; //doubles the size of the re-visitation window + gap = -gap; //inverts the modifier to the step + } + + } while (row < nRows); + //==========================================================================/ + + //============================ Wandering Phase =============================// + row = 0; //Resets the visitation to the first row of the memory matrix + for (tau = 1; tau <= timeCost; tau++) { + //Step is approximately half the number of all rows of the memory matrix for an odd tau; otherwise, it is -1 + step = ((tau & 1) == 0) ? -1 : (nRows >> 1) - 1; + do { + //Selects a pseudorandom index row* + //------------------------------------------------------------------------------------------ + instance = state[instance & 0xF]; + rowa = state[instance & 0xF] & (unsigned int)(nRows-1); + + //rowa = state[0] & (unsigned int)(nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + //rowa = state[0] % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + //Performs a reduced-round duplexing operation over M[row*] XOR M[prev], updating both M[row*] and M[row] + reducedDuplexRow(state, memMatrix[prev], memMatrix[rowa], memMatrix[row], nCols); + + //update prev: it now points to the last row ever computed + prev = row; + + //updates row: goes to the next row to be computed + //------------------------------------------------------------------------------------------ + row = (row + step) & (unsigned int)(nRows-1); //(USE THIS IF nRows IS A POWER OF 2) + //row = (row + step) % nRows; //(USE THIS FOR THE "GENERIC" CASE) + //------------------------------------------------------------------------------------------ + + } while (row != 0); + } + + //============================ Wrap-up Phase ===============================// + //Absorbs the last block of the memory matrix + absorbBlock(state, memMatrix[rowa]); + + //Squeezes the key + squeeze(state, K, (unsigned int) kLen); + + //========================= Freeing the memory =============================// + free(memMatrix); + free(wholeMatrix); + + return 0; +} diff --git a/lyra2/Lyra2.h b/lyra2/Lyra2.h new file mode 100644 index 000000000..a6aa87a21 --- /dev/null +++ b/lyra2/Lyra2.h @@ -0,0 +1,44 @@ +/** + * Header file for the Lyra2 Password Hashing Scheme (PHS). + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef LYRA2_H_ +#define LYRA2_H_ + +#include + +typedef unsigned char byte; + +//Block length required so Blake2's Initialization Vector (IV) is not overwritten (THIS SHOULD NOT BE MODIFIED) +#define BLOCK_LEN_BLAKE2_SAFE_INT64 8 //512 bits (=64 bytes, =8 uint64_t) +#define BLOCK_LEN_BLAKE2_SAFE_BYTES (BLOCK_LEN_BLAKE2_SAFE_INT64 * 8) //same as above, in bytes + + +#ifdef BLOCK_LEN_BITS + #define BLOCK_LEN_INT64 (BLOCK_LEN_BITS/64) //Block length: 768 bits (=96 bytes, =12 uint64_t) + #define BLOCK_LEN_BYTES (BLOCK_LEN_BITS/8) //Block length, in bytes +#else //default block lenght: 768 bits + #define BLOCK_LEN_INT64 12 //Block length: 768 bits (=96 bytes, =12 uint64_t) + #define BLOCK_LEN_BYTES (BLOCK_LEN_INT64 * 8) //Block length, in bytes +#endif + +int LYRA2(void *K, int64_t kLen, const void *pwd, int32_t pwdlen, const void *salt, int32_t saltlen, int64_t timeCost, const int16_t nRows, const int16_t nCols); + +int LYRA2_3(void *K, int64_t kLen, const void *pwd, int32_t pwdlen, const void *salt, int32_t saltlen, int64_t timeCost, const int16_t nRows, const int16_t nCols); + +#endif /* LYRA2_H_ */ diff --git a/lyra2/Sponge.c b/lyra2/Sponge.c new file mode 100644 index 000000000..a698229df --- /dev/null +++ b/lyra2/Sponge.c @@ -0,0 +1,410 @@ +/** + * A simple implementation of Blake2b's internal permutation + * in the form of a sponge. + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include "Sponge.h" +#include "Lyra2.h" + + +/** + * Initializes the Sponge State. The first 512 bits are set to zeros and the remainder + * receive Blake2b's IV as per Blake2b's specification. Note: Even though sponges + * typically have their internal state initialized with zeros, Blake2b's G function + * has a fixed point: if the internal state and message are both filled with zeros. the + * resulting permutation will always be a block filled with zeros; this happens because + * Blake2b does not use the constants originally employed in Blake2 inside its G function, + * relying on the IV for avoiding possible fixed points. + * + * @param state The 1024-bit array to be initialized + */ +void initState(uint64_t state[/*16*/]) { + //First 512 bis are zeros + memset(state, 0, 64); + //Remainder BLOCK_LEN_BLAKE2_SAFE_BYTES are reserved to the IV + state[8] = blake2b_IV[0]; + state[9] = blake2b_IV[1]; + state[10] = blake2b_IV[2]; + state[11] = blake2b_IV[3]; + state[12] = blake2b_IV[4]; + state[13] = blake2b_IV[5]; + state[14] = blake2b_IV[6]; + state[15] = blake2b_IV[7]; +} + +/** + * Execute Blake2b's G function, with all 12 rounds. + * + * @param v A 1024-bit (16 uint64_t) array to be processed by Blake2b's G function + */ +__inline static void blake2bLyra(uint64_t *v) { + ROUND_LYRA(0); + ROUND_LYRA(1); + ROUND_LYRA(2); + ROUND_LYRA(3); + ROUND_LYRA(4); + ROUND_LYRA(5); + ROUND_LYRA(6); + ROUND_LYRA(7); + ROUND_LYRA(8); + ROUND_LYRA(9); + ROUND_LYRA(10); + ROUND_LYRA(11); +} + +/** + * Executes a reduced version of Blake2b's G function with only one round + * @param v A 1024-bit (16 uint64_t) array to be processed by Blake2b's G function + */ +__inline static void reducedBlake2bLyra(uint64_t *v) { + ROUND_LYRA(0); +} + +/** + * Performs a squeeze operation, using Blake2b's G function as the + * internal permutation + * + * @param state The current state of the sponge + * @param out Array that will receive the data squeezed + * @param len The number of bytes to be squeezed into the "out" array + */ +void squeeze(uint64_t *state, byte *out, unsigned int len) +{ + int fullBlocks = len / BLOCK_LEN_BYTES; + byte *ptr = out; + int i; + //Squeezes full blocks + for (i = 0; i < fullBlocks; i++) { + memcpy(ptr, state, BLOCK_LEN_BYTES); + blake2bLyra(state); + ptr += BLOCK_LEN_BYTES; + } + + //Squeezes remaining bytes + memcpy(ptr, state, (len % BLOCK_LEN_BYTES)); +} + +/** + * Performs an absorb operation for a single block (BLOCK_LEN_INT64 words + * of type uint64_t), using Blake2b's G function as the internal permutation + * + * @param state The current state of the sponge + * @param in The block to be absorbed (BLOCK_LEN_INT64 words) + */ +void absorbBlock(uint64_t *state, const uint64_t *in) +{ + //XORs the first BLOCK_LEN_INT64 words of "in" with the current state + state[0] ^= in[0]; + state[1] ^= in[1]; + state[2] ^= in[2]; + state[3] ^= in[3]; + state[4] ^= in[4]; + state[5] ^= in[5]; + state[6] ^= in[6]; + state[7] ^= in[7]; + state[8] ^= in[8]; + state[9] ^= in[9]; + state[10] ^= in[10]; + state[11] ^= in[11]; + + //Applies the transformation f to the sponge's state + blake2bLyra(state); +} + +/** + * Performs an absorb operation for a single block (BLOCK_LEN_BLAKE2_SAFE_INT64 + * words of type uint64_t), using Blake2b's G function as the internal permutation + * + * @param state The current state of the sponge + * @param in The block to be absorbed (BLOCK_LEN_BLAKE2_SAFE_INT64 words) + */ +void absorbBlockBlake2Safe(uint64_t *state, const uint64_t *in) +{ + //XORs the first BLOCK_LEN_BLAKE2_SAFE_INT64 words of "in" with the current state + + state[0] ^= in[0]; + state[1] ^= in[1]; + state[2] ^= in[2]; + state[3] ^= in[3]; + state[4] ^= in[4]; + state[5] ^= in[5]; + state[6] ^= in[6]; + state[7] ^= in[7]; + + //Applies the transformation f to the sponge's state + blake2bLyra(state); +} + +/** + * Performs a reduced squeeze operation for a single row, from the highest to + * the lowest index, using the reduced-round Blake2b's G function as the + * internal permutation + * + * @param state The current state of the sponge + * @param rowOut Row to receive the data squeezed + */ +void reducedSqueezeRow0(uint64_t* state, uint64_t* rowOut, const uint32_t nCols) +{ + uint64_t* ptrWord = rowOut + (nCols-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to M[0][C-1] + unsigned int i; + //M[row][C-1-col] = H.reduced_squeeze() + for (i = 0; i < nCols; i++) { + ptrWord[0] = state[0]; + ptrWord[1] = state[1]; + ptrWord[2] = state[2]; + ptrWord[3] = state[3]; + ptrWord[4] = state[4]; + ptrWord[5] = state[5]; + ptrWord[6] = state[6]; + ptrWord[7] = state[7]; + ptrWord[8] = state[8]; + ptrWord[9] = state[9]; + ptrWord[10] = state[10]; + ptrWord[11] = state[11]; + + //Goes to next block (column) that will receive the squeezed data + ptrWord -= BLOCK_LEN_INT64; + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + } +} + +/** + * Performs a reduced duplex operation for a single row, from the highest to + * the lowest index, using the reduced-round Blake2b's G function as the + * internal permutation + * + * @param state The current state of the sponge + * @param rowIn Row to feed the sponge + * @param rowOut Row to receive the sponge's output + */ +void reducedDuplexRow1(uint64_t *state, uint64_t *rowIn, uint64_t *rowOut, const uint32_t nCols) +{ + uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev + uint64_t* ptrWordOut = rowOut + (nCols-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to row + unsigned int i; + + for (i = 0; i < nCols; i++) { + + //Absorbing "M[prev][col]" + state[0] ^= (ptrWordIn[0]); + state[1] ^= (ptrWordIn[1]); + state[2] ^= (ptrWordIn[2]); + state[3] ^= (ptrWordIn[3]); + state[4] ^= (ptrWordIn[4]); + state[5] ^= (ptrWordIn[5]); + state[6] ^= (ptrWordIn[6]); + state[7] ^= (ptrWordIn[7]); + state[8] ^= (ptrWordIn[8]); + state[9] ^= (ptrWordIn[9]); + state[10] ^= (ptrWordIn[10]); + state[11] ^= (ptrWordIn[11]); + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + + //M[row][C-1-col] = M[prev][col] XOR rand + ptrWordOut[0] = ptrWordIn[0] ^ state[0]; + ptrWordOut[1] = ptrWordIn[1] ^ state[1]; + ptrWordOut[2] = ptrWordIn[2] ^ state[2]; + ptrWordOut[3] = ptrWordIn[3] ^ state[3]; + ptrWordOut[4] = ptrWordIn[4] ^ state[4]; + ptrWordOut[5] = ptrWordIn[5] ^ state[5]; + ptrWordOut[6] = ptrWordIn[6] ^ state[6]; + ptrWordOut[7] = ptrWordIn[7] ^ state[7]; + ptrWordOut[8] = ptrWordIn[8] ^ state[8]; + ptrWordOut[9] = ptrWordIn[9] ^ state[9]; + ptrWordOut[10] = ptrWordIn[10] ^ state[10]; + ptrWordOut[11] = ptrWordIn[11] ^ state[11]; + + //Input: next column (i.e., next block in sequence) + ptrWordIn += BLOCK_LEN_INT64; + //Output: goes to previous column + ptrWordOut -= BLOCK_LEN_INT64; + } +} + +/** + * Performs a duplexing operation over "M[rowInOut][col] [+] M[rowIn][col]" (i.e., + * the wordwise addition of two columns, ignoring carries between words). The + * output of this operation, "rand", is then used to make + * "M[rowOut][(N_COLS-1)-col] = M[rowIn][col] XOR rand" and + * "M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)", where rotW is a 64-bit + * rotation to the left and N_COLS is a system parameter. + * + * @param state The current state of the sponge + * @param rowIn Row used only as input + * @param rowInOut Row used as input and to receive output after rotation + * @param rowOut Row receiving the output + * + */ +void reducedDuplexRowSetup(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, const uint32_t nCols) +{ + uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev + uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row* + uint64_t* ptrWordOut = rowOut + (nCols-1)*BLOCK_LEN_INT64; //In Lyra2: pointer to row + unsigned int i; + + for (i = 0; i < nCols; i++) { + + //Absorbing "M[prev] [+] M[row*]" + state[0] ^= (ptrWordIn[0] + ptrWordInOut[0]); + state[1] ^= (ptrWordIn[1] + ptrWordInOut[1]); + state[2] ^= (ptrWordIn[2] + ptrWordInOut[2]); + state[3] ^= (ptrWordIn[3] + ptrWordInOut[3]); + state[4] ^= (ptrWordIn[4] + ptrWordInOut[4]); + state[5] ^= (ptrWordIn[5] + ptrWordInOut[5]); + state[6] ^= (ptrWordIn[6] + ptrWordInOut[6]); + state[7] ^= (ptrWordIn[7] + ptrWordInOut[7]); + state[8] ^= (ptrWordIn[8] + ptrWordInOut[8]); + state[9] ^= (ptrWordIn[9] + ptrWordInOut[9]); + state[10] ^= (ptrWordIn[10] + ptrWordInOut[10]); + state[11] ^= (ptrWordIn[11] + ptrWordInOut[11]); + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + + //M[row][col] = M[prev][col] XOR rand + ptrWordOut[0] = ptrWordIn[0] ^ state[0]; + ptrWordOut[1] = ptrWordIn[1] ^ state[1]; + ptrWordOut[2] = ptrWordIn[2] ^ state[2]; + ptrWordOut[3] = ptrWordIn[3] ^ state[3]; + ptrWordOut[4] = ptrWordIn[4] ^ state[4]; + ptrWordOut[5] = ptrWordIn[5] ^ state[5]; + ptrWordOut[6] = ptrWordIn[6] ^ state[6]; + ptrWordOut[7] = ptrWordIn[7] ^ state[7]; + ptrWordOut[8] = ptrWordIn[8] ^ state[8]; + ptrWordOut[9] = ptrWordIn[9] ^ state[9]; + ptrWordOut[10] = ptrWordIn[10] ^ state[10]; + ptrWordOut[11] = ptrWordIn[11] ^ state[11]; + + //M[row*][col] = M[row*][col] XOR rotW(rand) + ptrWordInOut[0] ^= state[11]; + ptrWordInOut[1] ^= state[0]; + ptrWordInOut[2] ^= state[1]; + ptrWordInOut[3] ^= state[2]; + ptrWordInOut[4] ^= state[3]; + ptrWordInOut[5] ^= state[4]; + ptrWordInOut[6] ^= state[5]; + ptrWordInOut[7] ^= state[6]; + ptrWordInOut[8] ^= state[7]; + ptrWordInOut[9] ^= state[8]; + ptrWordInOut[10] ^= state[9]; + ptrWordInOut[11] ^= state[10]; + + //Inputs: next column (i.e., next block in sequence) + ptrWordInOut += BLOCK_LEN_INT64; + ptrWordIn += BLOCK_LEN_INT64; + //Output: goes to previous column + ptrWordOut -= BLOCK_LEN_INT64; + } +} + +/** + * Performs a duplexing operation over "M[rowInOut][col] [+] M[rowIn][col]" (i.e., + * the wordwise addition of two columns, ignoring carries between words). The + * output of this operation, "rand", is then used to make + * "M[rowOut][col] = M[rowOut][col] XOR rand" and + * "M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand)", where rotW is a 64-bit + * rotation to the left. + * + * @param state The current state of the sponge + * @param rowIn Row used only as input + * @param rowInOut Row used as input and to receive output after rotation + * @param rowOut Row receiving the output + * + */ +void reducedDuplexRow(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, const uint32_t nCols) +{ + uint64_t* ptrWordInOut = rowInOut; //In Lyra2: pointer to row* + uint64_t* ptrWordIn = rowIn; //In Lyra2: pointer to prev + uint64_t* ptrWordOut = rowOut; //In Lyra2: pointer to row + unsigned int i; + + for (i = 0; i < nCols; i++) { + + //Absorbing "M[prev] [+] M[row*]" + state[0] ^= (ptrWordIn[0] + ptrWordInOut[0]); + state[1] ^= (ptrWordIn[1] + ptrWordInOut[1]); + state[2] ^= (ptrWordIn[2] + ptrWordInOut[2]); + state[3] ^= (ptrWordIn[3] + ptrWordInOut[3]); + state[4] ^= (ptrWordIn[4] + ptrWordInOut[4]); + state[5] ^= (ptrWordIn[5] + ptrWordInOut[5]); + state[6] ^= (ptrWordIn[6] + ptrWordInOut[6]); + state[7] ^= (ptrWordIn[7] + ptrWordInOut[7]); + state[8] ^= (ptrWordIn[8] + ptrWordInOut[8]); + state[9] ^= (ptrWordIn[9] + ptrWordInOut[9]); + state[10] ^= (ptrWordIn[10] + ptrWordInOut[10]); + state[11] ^= (ptrWordIn[11] + ptrWordInOut[11]); + + //Applies the reduced-round transformation f to the sponge's state + reducedBlake2bLyra(state); + + //M[rowOut][col] = M[rowOut][col] XOR rand + ptrWordOut[0] ^= state[0]; + ptrWordOut[1] ^= state[1]; + ptrWordOut[2] ^= state[2]; + ptrWordOut[3] ^= state[3]; + ptrWordOut[4] ^= state[4]; + ptrWordOut[5] ^= state[5]; + ptrWordOut[6] ^= state[6]; + ptrWordOut[7] ^= state[7]; + ptrWordOut[8] ^= state[8]; + ptrWordOut[9] ^= state[9]; + ptrWordOut[10] ^= state[10]; + ptrWordOut[11] ^= state[11]; + + //M[rowInOut][col] = M[rowInOut][col] XOR rotW(rand) + ptrWordInOut[0] ^= state[11]; + ptrWordInOut[1] ^= state[0]; + ptrWordInOut[2] ^= state[1]; + ptrWordInOut[3] ^= state[2]; + ptrWordInOut[4] ^= state[3]; + ptrWordInOut[5] ^= state[4]; + ptrWordInOut[6] ^= state[5]; + ptrWordInOut[7] ^= state[6]; + ptrWordInOut[8] ^= state[7]; + ptrWordInOut[9] ^= state[8]; + ptrWordInOut[10] ^= state[9]; + ptrWordInOut[11] ^= state[10]; + + //Goes to next block + ptrWordOut += BLOCK_LEN_INT64; + ptrWordInOut += BLOCK_LEN_INT64; + ptrWordIn += BLOCK_LEN_INT64; + } +} + +/** + * Prints an array of unsigned chars + */ +void printArray(unsigned char *array, unsigned int size, char *name) +{ + unsigned int i; + printf("%s: ", name); + for (i = 0; i < size; i++) { + printf("%2x|", array[i]); + } + printf("\n"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lyra2/Sponge.h b/lyra2/Sponge.h new file mode 100644 index 000000000..7fcd09342 --- /dev/null +++ b/lyra2/Sponge.h @@ -0,0 +1,88 @@ +/** + * Header file for Blake2b's internal permutation in the form of a sponge. + * This code is based on the original Blake2b's implementation provided by + * Samuel Neves (https://blake2.net/) + * + * Author: The Lyra PHC team (http://www.lyra-kdf.net/) -- 2014. + * + * This software is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SPONGE_H_ +#define SPONGE_H_ + +#include + +/* Blake2b IV Array */ +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +/* Blake2b's rotation */ +static __inline uint64_t rotr64(const uint64_t w, const unsigned c) { +#ifdef _MSC_VER + return _rotr64(w, c); +#else + return ( w >> c ) | ( w << ( 64 - c ) ); +#endif +} + +/* Blake2b's G function */ +#define G(r,i,a,b,c,d) do { \ + a = a + b; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + + +/*One Round of the Blake2b's compression function*/ +#define ROUND_LYRA(r) \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); + +//---- Housekeeping +void initState(uint64_t state[/*16*/]); + +//---- Squeezes +void squeeze(uint64_t *state, unsigned char *out, unsigned int len); +void reducedSqueezeRow0(uint64_t* state, uint64_t* row, const uint32_t nCols); + +//---- Absorbs +void absorbBlock(uint64_t *state, const uint64_t *in); +void absorbBlockBlake2Safe(uint64_t *state, const uint64_t *in); + +//---- Duplexes +void reducedDuplexRow1(uint64_t *state, uint64_t *rowIn, uint64_t *rowOut, const uint32_t nCols); +void reducedDuplexRowSetup(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, const uint32_t nCols); +void reducedDuplexRow(uint64_t *state, uint64_t *rowIn, uint64_t *rowInOut, uint64_t *rowOut, const uint32_t nCols); + +//---- Misc +void printArray(unsigned char *array, unsigned int size, char *name); + +#endif /* SPONGE_H_ */ diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/miner.h b/miner.h index bc77a1f4d..34574030f 100644 --- a/miner.h +++ b/miner.h @@ -1,11 +1,33 @@ #ifndef __MINER_H__ #define __MINER_H__ -#include "cpuminer-config.h" +#include + +#define USER_AGENT PACKAGE_NAME "/" PACKAGE_VERSION +#define MAX_CPUS 16 + +#ifdef _MSC_VER + +#undef USE_ASM /* to fix */ + +#ifdef NOASM +#undef USE_ASM +#endif + +/* missing arch defines for msvc */ +#if defined(_M_X64) +#define __i386__ 1 +#define __x86_64__ 1 +#elif defined(_M_X86) +#define __i386__ 1 +#endif + +#endif /* _MSC_VER */ #include #include #include + #include #include #include @@ -18,6 +40,7 @@ # include # endif #endif + #ifdef HAVE_ALLOCA_H # include #elif !defined alloca @@ -38,6 +61,7 @@ void *alloca (size_t); #ifdef HAVE_SYSLOG_H #include +#define LOG_BLUE 0x10 /* unique value */ #else enum { LOG_ERR, @@ -45,23 +69,25 @@ enum { LOG_NOTICE, LOG_INFO, LOG_DEBUG, + /* custom notices */ + LOG_BLUE = 0x10, }; #endif -#undef unlikely -#undef likely -#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) -#define unlikely(expr) (__builtin_expect(!!(expr), 0)) -#define likely(expr) (__builtin_expect(!!(expr), 1)) -#else -#define unlikely(expr) (expr) -#define likely(expr) (expr) -#endif +#include "compat.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif +static inline bool is_windows(void) { +#ifdef WIN32 + return 1; +#else + return 0; +#endif +} + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) #define WANT_BUILTIN_BSWAP #else @@ -82,6 +108,8 @@ static inline uint32_t swab32(uint32_t v) #include #endif +typedef unsigned char uchar; + #if !HAVE_DECL_BE32DEC static inline uint32_t be32dec(const void *pp) { @@ -122,13 +150,32 @@ static inline void le32enc(void *pp, uint32_t x) } #endif +#if !HAVE_DECL_LE16DEC +static inline uint16_t le16dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + return ((uint16_t)(p[0]) + ((uint16_t)(p[1]) << 8)); +} +#endif + +#if !HAVE_DECL_LE16ENC +static inline void le16enc(void *pp, uint16_t x) +{ + uint8_t *p = (uint8_t *)pp; + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; +} +#endif + #if JANSSON_MAJOR_VERSION >= 2 -#define JSON_LOADS(str, err_ptr) json_loads((str), 0, (err_ptr)) +#define JSON_LOADS(str, err_ptr) json_loads(str, 0, err_ptr) +#define JSON_LOADF(path, err_ptr) json_load_file(path, 0, err_ptr) #else -#define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr)) +#define JSON_LOADS(str, err_ptr) json_loads(str, err_ptr) +#define JSON_LOADF(path, err_ptr) json_load_file(path, err_ptr) #endif -#define USER_AGENT PACKAGE_NAME "/" PACKAGE_VERSION +json_t* json_load_url(char* cfg_url, json_error_t *err); void sha256_init(uint32_t *state); void sha256_transform(uint32_t *state, const uint32_t *block, int swap); @@ -149,108 +196,225 @@ void sha256_transform_8way(uint32_t *state, const uint32_t *block, int swap); #endif #endif -extern int scanhash_sha256d(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern unsigned char *scrypt_buffer_alloc(int N); -extern int scanhash_scrypt(int thr_id, uint32_t *pdata, - unsigned char *scratchbuf, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done, int N); - -extern int scanhash_keccak(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_heavy(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_quark(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern void init_quarkhash_contexts(); - -extern int scanhash_skein(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_ink(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern void init_blakehash_contexts(); - -extern int scanhash_blake(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_fresh(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_x11(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_x13(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_x14(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern int scanhash_x15(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); - -extern void cryptonight_hash(void* output, const void* input, size_t input_len); +struct work; + +int scanhash_allium(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_axiom(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_bastion(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_blake(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_blakecoin(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_blake2b(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_blake2s(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_bmw(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_cryptolight(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_cryptonight(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_c11(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_decred(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_drop(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_fresh(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_geek(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_groestl(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_heavy(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_ink(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_keccak(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_jha(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_lbry(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_luffa(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_lyra2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_lyra2rev2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_lyra2v3(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_myriad(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_neoscrypt(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, uint32_t profile); +int scanhash_nist5(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_pentablake(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_phi1612(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_phi2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_pluck(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, + unsigned char *scratchbuf, int N); +int scanhash_quark(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +void init_quarkhash_contexts(); +int scanhash_qubit(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_rf256(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_sha256d(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +unsigned char *scrypt_buffer_alloc(int N); +int scanhash_scrypt(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, + unsigned char *scratchbuf, uint32_t N); +int scanhash_scryptjane(int Nfactor, int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_sia(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_sib(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_skein(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_skein2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_sonoa(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_s3(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_timetravel(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_bitcore(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_tribus(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_veltor(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x11evo(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x11(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x12(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x13(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x14(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x15(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x16r(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x16rv2(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x16s(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x17(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_x20r(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_xevan(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_yescrypt(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_yescryptr8(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_yescryptr16(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_yescryptr32(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); +int scanhash_zr5(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done); + +/* api related */ +void *api_thread(void *userdata); + +struct cpu_info { + int thr_id; + int accepted; + int rejected; + double khashes; + bool has_monitoring; + float cpu_temp; + int cpu_fan; + uint32_t cpu_clock; +}; -extern int scanhash_cryptonight(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done); +struct thr_api { + int id; + pthread_t pth; + struct thread_q *q; +}; +/* end of api */ struct thr_info { - int id; - pthread_t pth; + int id; + pthread_t pth; + pthread_attr_t attr; struct thread_q *q; + struct cpu_info cpu; }; struct work_restart { - volatile unsigned long restart; - char padding[128 - sizeof(unsigned long)]; + volatile uint8_t restart; + char padding[128 - sizeof(uint8_t)]; }; extern bool opt_debug; +extern bool opt_benchmark; extern bool opt_protocol; +extern bool opt_showdiff; +extern bool opt_quiet; extern bool opt_redirect; +extern int opt_priority; extern int opt_timeout; extern bool want_longpoll; extern bool have_longpoll; +extern bool have_gbt; +extern bool allow_getwork; extern bool want_stratum; extern bool have_stratum; +extern bool opt_stratum_stats; extern char *opt_cert; extern char *opt_proxy; extern long opt_proxy_type; extern bool use_syslog; +extern bool use_colors; extern pthread_mutex_t applog_lock; extern struct thr_info *thr_info; extern int longpoll_thr_id; extern int stratum_thr_id; +extern int api_thr_id; +extern int opt_n_threads; +extern int num_cpus; extern struct work_restart *work_restart; -extern bool jsonrpc_2; -extern bool aes_ni_supported; +extern uint32_t opt_work_size; +extern double *thr_hashrates; +extern uint64_t global_hashrate; +extern double stratum_diff; +extern double net_diff; +extern double net_hashrate; #define JSON_RPC_LONGPOLL (1 << 0) #define JSON_RPC_QUIET_404 (1 << 1) #define JSON_RPC_IGNOREERR (1 << 2) -extern void applog(int prio, const char *fmt, ...); +#define JSON_BUF_LEN 512 + +#define CL_N "\x1B[0m" +#define CL_RED "\x1B[31m" +#define CL_GRN "\x1B[32m" +#define CL_YLW "\x1B[33m" +#define CL_BLU "\x1B[34m" +#define CL_MAG "\x1B[35m" +#define CL_CYN "\x1B[36m" + +#define CL_BLK "\x1B[22;30m" /* black */ +#define CL_RD2 "\x1B[22;31m" /* red */ +#define CL_GR2 "\x1B[22;32m" /* green */ +#define CL_BRW "\x1B[22;33m" /* brown */ +#define CL_BL2 "\x1B[22;34m" /* blue */ +#define CL_MA2 "\x1B[22;35m" /* magenta */ +#define CL_CY2 "\x1B[22;36m" /* cyan */ +#define CL_SIL "\x1B[22;37m" /* gray */ + +#ifdef WIN32 +#define CL_GRY "\x1B[01;30m" /* dark gray */ +#else +#define CL_GRY "\x1B[90m" /* dark gray selectable in putty */ +#endif +#define CL_LRD "\x1B[01;31m" /* light red */ +#define CL_LGR "\x1B[01;32m" /* light green */ +#define CL_YL2 "\x1B[01;33m" /* yellow */ +#define CL_LBL "\x1B[01;34m" /* light blue */ +#define CL_LMA "\x1B[01;35m" /* light magenta */ +#define CL_LCY "\x1B[01;36m" /* light cyan */ + +#define CL_WHT "\x1B[01;37m" /* white */ + +void applog(int prio, const char *fmt, ...); +void restart_threads(void); extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req, int *curl_err, int flags); -extern char *bin2hex(const unsigned char *p, size_t len); -extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); -extern int timeval_subtract(struct timeval *result, struct timeval *x, - struct timeval *y); -extern bool fulltest(const uint32_t *hash, const uint32_t *target); -extern void diff_to_target(uint32_t *target, double diff); +void bin2hex(char *s, const unsigned char *p, size_t len); +char *abin2hex(const unsigned char *p, size_t len); +bool hex2bin(unsigned char *p, const char *hexstr, size_t len); +bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen); +int varint_encode(unsigned char *p, uint64_t n); +size_t address_to_script(unsigned char *out, size_t outsz, const char *addr); +int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); +bool fulltest(const uint32_t *hash, const uint32_t *target); +void work_set_target(struct work* work, double diff); +double target_to_diff(uint32_t* target); + +double hash_target_ratio(uint32_t* hash, uint32_t* target); +void work_set_target_ratio(struct work* work, uint32_t* hash); + +void get_currentalgo(char* buf, int sz); +bool has_aes_ni(void); +void cpu_bestfeature(char *outbuf, size_t maxsz); +void cpu_getname(char *outbuf, size_t maxsz); +void cpu_getmodelid(char *outbuf, size_t maxsz); +float cpu_temp(int core); struct work { - uint32_t data[32]; - uint32_t target[8]; + uint32_t data[48]; + uint32_t target[8]; - char *job_id; - size_t xnonce2_len; - unsigned char *xnonce2; + double targetdiff; + double shareratio; + double sharediff; + uint32_t resnonce; + + int height; + char *txs; + char *workid; + + char *job_id; + size_t xnonce2_len; + unsigned char *xnonce2; }; struct stratum_job { @@ -264,6 +428,7 @@ struct stratum_job { unsigned char version[4]; unsigned char nbits[4]; unsigned char ntime[4]; + unsigned char extra[64]; // like lbry claimtrie bool clean; double diff; }; @@ -280,6 +445,7 @@ struct stratum_ctx { pthread_mutex_t sock_lock; double next_diff; + double sharediff; char *session_id; size_t xnonce1_size; @@ -288,6 +454,8 @@ struct stratum_ctx { struct stratum_job job; struct work work; pthread_mutex_t work_lock; + + int bloc_height; }; bool stratum_socket_full(struct stratum_ctx *sctx, int timeout); @@ -299,16 +467,108 @@ bool stratum_subscribe(struct stratum_ctx *sctx); bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass); bool stratum_handle_method(struct stratum_ctx *sctx, const char *s); -extern bool rpc2_job_decode(const json_t *job, struct work *work); -extern bool rpc2_login_decode(const json_t *val); +/* rpc 2.0 (xmr) */ +extern bool jsonrpc_2; +extern bool aes_ni_supported; +extern char rpc2_id[64]; +extern char *rpc2_blob; +extern size_t rpc2_bloblen; +extern uint32_t rpc2_target; +extern char *rpc2_job_id; + +json_t *json_rpc2_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req, int *curl_err, int flags); +bool rpc2_login(CURL *curl); +bool rpc2_login_decode(const json_t *val); +bool rpc2_workio_login(CURL *curl); +bool rpc2_stratum_job(struct stratum_ctx *sctx, json_t *params); +bool rpc2_job_decode(const json_t *job, struct work *work); struct thread_q; -extern struct thread_q *tq_new(void); -extern void tq_free(struct thread_q *tq); -extern bool tq_push(struct thread_q *tq, void *data); -extern void *tq_pop(struct thread_q *tq, const struct timespec *abstime); -extern void tq_freeze(struct thread_q *tq); -extern void tq_thaw(struct thread_q *tq); +struct thread_q *tq_new(void); +void tq_free(struct thread_q *tq); +bool tq_push(struct thread_q *tq, void *data); +void *tq_pop(struct thread_q *tq, const struct timespec *abstime); +void tq_freeze(struct thread_q *tq); +void tq_thaw(struct thread_q *tq); + +void parse_arg(int key, char *arg); +void parse_config(json_t *config, char *ref); +void proper_exit(int reason); + +void applog_compare_hash(void *hash, void *hash_ref); +void applog_hex(void *data, int len); +void applog_hash(void *hash); +void applog_hash64(void *hash); +void format_hashrate(double hashrate, char *output); +void print_hash_tests(void); + +void sha256d(unsigned char *hash, const unsigned char *data, int len); +void allium_hash(void *state, const void *input); +void axiomhash(void *state, const void *input); +void bastionhash(void *output, const void *input); +void blakehash(void *state, const void *input); +void blakecoinhash(void *state, const void *input); +void blake2s_hash(void *output, const void *input); +void blake2b_hash(void *output, const void *input); +void bmwhash(void *output, const void *input); +void c11hash(void *output, const void *input); +void cryptolight_hash(void* output, const void* input); +void cryptonight_hash(void* output, const void* input); +void cryptonight_hash_v1(void* output, const void* input); +void decred_hash(void *output, const void *input); +void droplp_hash(void *output, const void *input); +void groestlhash(void *output, const void *input); +void heavyhash(unsigned char* output, const unsigned char* input, int len); +void quarkhash(void *state, const void *input); +void freshhash(void* output, const void* input, uint32_t len); +void geekhash(void *output, const void *input); +void keccakhash(void *state, const void *input); +void inkhash(void *state, const void *input); /* shavite */ +void jha_hash(void *output, const void *input); +void lbry_hash(void *output, const void *input); +void luffahash(void *output, const void *input); +void lyra2_hash(void *state, const void *input); +void lyra2rev2_hash(void *state, const void *input); +void lyra2v3_hash(void *state, const void *input); +void myriadhash(void *output, const void *input); +void neoscrypt(unsigned char *output, const unsigned char *password, uint32_t profile); +void nist5hash(void *output, const void *input); +void phi1612_hash(void *state, const void *input); +void phi2_hash(void *state, const void *input); +void pluck_hash(uint32_t *hash, const uint32_t *data, uchar *hashbuffer, const int N); +void pentablakehash(void *output, const void *input); +void qubithash(void *output, const void *input); +void rf256_hash(void *out, const void *in, size_t len); +void scrypthash(void *output, const void *input, uint32_t N); +void scryptjanehash(void *output, const void *input, uint32_t Nfactor); +void sibhash(void *output, const void *input); +void skeinhash(void *state, const void *input); +void skein2hash(void *state, const void *input); +void sonoa_hash(void *output, const void *input); +void s3hash(void *output, const void *input); +void timetravel_hash(void *output, const void *input); +void bitcore_hash(void *output, const void *input); +void tribus_hash(void *output, const void *input); +void veltor_hash(void *output, const void *input); +void xevan_hash(void *output, const void *input); +void x11evo_hash(void *output, const void *input); +void x11hash(void *output, const void *input); +void x12hash(void *output, const void *input); +void x13hash(void *output, const void *input); +void x14hash(void *output, const void *input); +void x15hash(void *output, const void *input); +void x16r_hash(void *output, const void *input); +void x16rv2_hash(void *output, const void *input); +void x16s_hash(void *output, const void *input); +void x17hash(void *output, const void *input); +void x20r_hash(void *output, const void *input); +void zr5hash(void *output, const void *input); +void yescrypthash(void *output, const void *input); +void yescrypt_hash_r8(const char* input, char* output, uint32_t len); +void yescrypt_hash_r16(const char* input, char* output, uint32_t len); +void yescrypt_hash_r32(const char* input, char* output, uint32_t len); +void zr5hash_pok(void *output, uint32_t *pdata); + #endif /* __MINER_H__ */ diff --git a/mingw64.sh b/mingw64.sh new file mode 100644 index 000000000..07249baf2 --- /dev/null +++ b/mingw64.sh @@ -0,0 +1,31 @@ +./autogen.sh + +CURL_PREFIX=/usr/local +SSL_PREFIX=/usr/local/ssl + +# gcc 4.4 +extracflags="-O3 -Wall -D_REENTRANT -fmerge-all-constants" # -funroll-loops -fvariable-expansion-in-unroller -fbranch-target-load-optimize2 -fsched2-use-superblocks -falign-loops=16 -falign-functions=16 -falign-jumps=16 -falign-labels=16" + +# gcc 4.8+ +# extracflags="$extracflags -Ofast -fuse-linker-plugin -ftree-loop-if-convert-stores" # -flto " + +# extracflags="$extracflags -march=native" + +# extracflags="-pg -static -fno-inline-small-functions" +CFLAGS="-DCURL_STATICLIB -DOPENSSL_NO_ASM -DUSE_ASM -static-libgcc $extracflags" +# CPPFLAGS="" + +# icon +windres res/icon.rc icon.o + +./configure --build=x86_64-w64-mingw32 --with-crypto=$SSL_PREFIX --with-curl=$CURL_PREFIX \ + CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" LDFLAGS="icon.o" + +make + +strip -p --strip-debug --strip-unneeded cpuminer.exe + +if [ -e sign.sh ] ; then +. sign.sh +fi + diff --git a/nomacro.pl b/nomacro.pl old mode 100644 new mode 100755 index e91cda34b..111c0274f --- a/nomacro.pl +++ b/nomacro.pl @@ -10,7 +10,7 @@ use strict; -foreach my $f (<*.S>) { +foreach my $f () { rename $f, "$f.orig"; open FIN, "$f.orig"; open FOUT, ">$f"; diff --git a/quark.c b/quark.c deleted file mode 100644 index b00170dbd..000000000 --- a/quark.c +++ /dev/null @@ -1,252 +0,0 @@ -#include "cpuminer-config.h" -#include "miner.h" - -#include -#include - -#include "sha3/sph_blake.h" -#include "sha3/sph_bmw.h" -#include "sha3/sph_groestl.h" -#include "sha3/sph_jh.h" -#include "sha3/sph_keccak.h" -#include "sha3/sph_skein.h" - - -/* Move init out of loop, so init once externally, and then use one single memcpy with that bigger memory block */ -typedef struct { - sph_blake512_context blake1, blake2; - sph_bmw512_context bmw1, bmw2; - sph_groestl512_context groestl1, groestl2; - sph_skein512_context skein1, skein2; - sph_jh512_context jh1, jh2; - sph_keccak512_context keccak1, keccak2; -} quarkhash_context_holder; - -static quarkhash_context_holder base_contexts; - -void init_quarkhash_contexts() -{ - sph_blake512_init(&base_contexts.blake1); - sph_bmw512_init(&base_contexts.bmw1); - sph_groestl512_init(&base_contexts.groestl1); - sph_skein512_init(&base_contexts.skein1); - sph_groestl512_init(&base_contexts.groestl2); - sph_jh512_init(&base_contexts.jh1); - sph_blake512_init(&base_contexts.blake2); - sph_bmw512_init(&base_contexts.bmw2); - sph_keccak512_init(&base_contexts.keccak1); - sph_skein512_init(&base_contexts.skein2); - sph_keccak512_init(&base_contexts.keccak2); - sph_jh512_init(&base_contexts.jh2); -} - -static void quarkhash(void *state, const void *input) -{ -// sph_blake512_context ctx_blake; -// sph_bmw512_context ctx_bmw; -// sph_groestl512_context ctx_groestl; -// sph_jh512_context ctx_jh; -// sph_keccak512_context ctx_keccak; -// sph_skein512_context ctx_skein; -// static unsigned char pblank[1]; - - quarkhash_context_holder ctx; - - uint32_t mask = 8; - uint32_t zero = 0; - - //these uint512 in the c++ source of the client are backed by an array of uint32 - uint32_t hashA[16], hashB[16]; - - - //do one memcopy to get fresh contexts, its faster even with a larger block then issuing 9 memcopies - memcpy(&ctx, &base_contexts, sizeof(base_contexts)); - - -// sph_blake512_init(&ctx.blake1); - sph_blake512 (&ctx.blake1, input, 80); - sph_blake512_close (&ctx.blake1, hashA); //0 - -// sph_bmw512_init(&ctx.bmw1); - sph_bmw512 (&ctx.bmw1, hashA, 64); //0 - sph_bmw512_close(&ctx.bmw1, hashB); //1 - - if ((hashB[0] & mask) != zero) //1 - { -// sph_groestl512_init(&ctx.groestl1); - sph_groestl512 (&ctx.groestl1, hashB, 64); //1 - sph_groestl512_close(&ctx.groestl1, hashA); //2 - } - else - { -// sph_skein512_init(&ctx.skein1); - sph_skein512 (&ctx.skein1, hashB, 64); //1 - sph_skein512_close(&ctx.skein1, hashA); //2 - } - -// sph_groestl512_init(&ctx.groestl2); - sph_groestl512 (&ctx.groestl2, hashA, 64); //2 - sph_groestl512_close(&ctx.groestl2, hashB); //3 - -// sph_jh512_init(&ctx.jh1); - sph_jh512 (&ctx.jh1, hashB, 64); //3 - sph_jh512_close(&ctx.jh1, hashA); //4 - - if ((hashA[0] & mask) != zero) //4 - { -// sph_blake512_init(&ctx.blake2); - sph_blake512 (&ctx.blake2, hashA, 64); // - sph_blake512_close(&ctx.blake2, hashB); //5 - } - else - { -// sph_bmw512_init(&ctx.bmw2); - sph_bmw512 (&ctx.bmw2, hashA, 64); //4 - sph_bmw512_close(&ctx.bmw2, hashB); //5 - } - -// sph_keccak512_init(&ctx.keccak1); - sph_keccak512 (&ctx.keccak1, hashB, 64); //5 - sph_keccak512_close(&ctx.keccak1, hashA); //6 - -// sph_skein512_init(&ctx.skein2); - sph_skein512 (&ctx.skein2, hashA, 64); //6 - sph_skein512_close(&ctx.skein2, hashB); //7 - - if ((hashB[0] & mask) != zero) //7 - { -// sph_keccak512_init(&ctx.keccak2); - sph_keccak512 (&ctx.keccak2, hashB, 64); // - sph_keccak512_close(&ctx.keccak2, hashA); //8 - } - else - { -// sph_jh512_init(&ctx.jh2); - sph_jh512 (&ctx.jh2, hashB, 64); //7 - sph_jh512_close(&ctx.jh2, hashA); //8 - } - - memcpy(state, hashA, 32); - -/* - int ii; - printf("result: "); - for (ii=0; ii < 32; ii++) - { - printf ("%.2x",((uint8_t*)state)[ii]); - }; - printf ("\n"); -*/ -} - -int scanhash_quark(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t n = pdata[19] - 1; - const uint32_t first_nonce = pdata[19]; - const uint32_t Htarg = ptarget[7]; - - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - - //char testdata[] = {"\x70\x00\x00\x00\x5d\x38\x5b\xa1\x14\xd0\x79\x97\x0b\x29\xa9\x41\x8f\xd0\x54\x9e\x7d\x68\xa9\x5c\x7f\x16\x86\x21\xa3\x14\x20\x10\x00\x00\x00\x00\x57\x85\x86\xd1\x49\xfd\x07\xb2\x2f\x3a\x8a\x34\x7c\x51\x6d\xe7\x05\x2f\x03\x4d\x2b\x76\xff\x68\xe0\xd6\xec\xff\x9b\x77\xa4\x54\x89\xe3\xfd\x51\x17\x32\x01\x1d\xf0\x73\x10\x00"}; - - //we need bigendian data... - //lessons learned: do NOT endianchange directly in pdata, this will all proof-of-works be considered as stale from minerd.... - int kk=0; - for (; kk < 32; kk++) - { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; - -// if (opt_debug) -// { -// applog(LOG_DEBUG, "Thr: %02d, firstN: %08x, maxN: %08x, ToDo: %d", thr_id, first_nonce, max_nonce, max_nonce-first_nonce); -// } - - /* I'm to lazy to put the loop in an inline function... so dirty copy'n'paste.... */ - /* i know that i could set a variable, but i don't know how the compiler will optimize it, not that then the cpu needs to load the value *everytime* in a register */ - if (ptarget[7]==0) { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - quarkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFFFF)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - quarkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFFF0)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - quarkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFF00)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - quarkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFF000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else if (ptarget[7]<=0xFFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - quarkhash(hash64, &endiandata); - if (((hash64[7]&0xFFFF0000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - quarkhash(hash64, &endiandata); - if (fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - - - *hashes_done = n - first_nonce + 1; - pdata[19] = n; - return 0; -} diff --git a/res/cpuminer.ico b/res/cpuminer.ico new file mode 100644 index 000000000..950b6d4c2 Binary files /dev/null and b/res/cpuminer.ico differ diff --git a/res/cpuminer.rc b/res/cpuminer.rc new file mode 100644 index 000000000..76c73755d --- /dev/null +++ b/res/cpuminer.rc @@ -0,0 +1,105 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "cpuminer.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,3,6,0 + PRODUCTVERSION 1,3,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "FileVersion", "1.3.6" + VALUE "LegalCopyright", "Copyright (C) 2019" + VALUE "ProductName", "cpuminer-multi" + VALUE "ProductVersion", "1.3.6" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/res/cpuminer.svg b/res/cpuminer.svg new file mode 100644 index 000000000..55eff3afa --- /dev/null +++ b/res/cpuminer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/icon.rc b/res/icon.rc new file mode 100644 index 000000000..854bd4c27 --- /dev/null +++ b/res/icon.rc @@ -0,0 +1 @@ +0 ICON cpuminer.ico diff --git a/res/resource.h b/res/resource.h new file mode 100644 index 000000000..0e452277c Binary files /dev/null and b/res/resource.h differ diff --git a/res/setup.ico b/res/setup.ico new file mode 100644 index 000000000..0b68582b5 Binary files /dev/null and b/res/setup.ico differ diff --git a/scryptjane/scrypt-conf.h b/scryptjane/scrypt-conf.h new file mode 100644 index 000000000..46685a518 --- /dev/null +++ b/scryptjane/scrypt-conf.h @@ -0,0 +1,28 @@ +/* + pick the best algo at runtime or compile time? + ---------------------------------------------- + SCRYPT_CHOOSE_COMPILETIME (gcc only!) + SCRYPT_CHOOSE_RUNTIME +*/ +#define SCRYPT_CHOOSE_RUNTIME + + +/* + hash function to use + ------------------------------- + SCRYPT_BLAKE256 + SCRYPT_BLAKE512 + SCRYPT_SHA256 + SCRYPT_SHA512 + SCRYPT_SKEIN512 +*/ +//#define SCRYPT_SHA256 + + +/* + block mixer to use + ----------------------------- + SCRYPT_CHACHA + SCRYPT_SALSA +*/ +//#define SCRYPT_SALSA diff --git a/scryptjane/scrypt-jane-chacha.h b/scryptjane/scrypt-jane-chacha.h index 41d96e5ee..c4d44c24b 100644 --- a/scryptjane/scrypt-jane-chacha.h +++ b/scryptjane/scrypt-jane-chacha.h @@ -18,6 +18,10 @@ typedef uint32_t scrypt_mix_word_t; #if defined(SCRYPT_CHACHA_AVX) #define SCRYPT_CHUNKMIX_FN scrypt_ChunkMix_avx + #if defined(X86_INTRINSIC_AVX) + #define SCRYPT_CHUNKMIX_1_FN scrypt_ChunkMix_avx_1 + #define SCRYPT_CHUNKMIX_1_XOR_FN scrypt_ChunkMix_avx_1_xor + #endif #define SCRYPT_ROMIX_FN scrypt_ROMix_avx #define SCRYPT_MIX_FN chacha_core_avx #define SCRYPT_ROMIX_TANGLE_FN scrypt_romix_nop @@ -27,6 +31,10 @@ typedef uint32_t scrypt_mix_word_t; #if defined(SCRYPT_CHACHA_SSSE3) #define SCRYPT_CHUNKMIX_FN scrypt_ChunkMix_ssse3 + #if defined(X86_INTRINSIC_SSSE3) + #define SCRYPT_CHUNKMIX_1_FN scrypt_ChunkMix_ssse3_1 + #define SCRYPT_CHUNKMIX_1_XOR_FN scrypt_ChunkMix_ssse3_1_xor + #endif #define SCRYPT_ROMIX_FN scrypt_ROMix_ssse3 #define SCRYPT_MIX_FN chacha_core_ssse3 #define SCRYPT_ROMIX_TANGLE_FN scrypt_romix_nop @@ -36,6 +44,10 @@ typedef uint32_t scrypt_mix_word_t; #if defined(SCRYPT_CHACHA_SSE2) #define SCRYPT_CHUNKMIX_FN scrypt_ChunkMix_sse2 + #if defined(X86_INTRINSIC_SSE2) + #define SCRYPT_CHUNKMIX_1_FN scrypt_ChunkMix_sse2_1 + #define SCRYPT_CHUNKMIX_1_XOR_FN scrypt_ChunkMix_sse2_1_xor + #endif #define SCRYPT_ROMIX_FN scrypt_ROMix_sse2 #define SCRYPT_MIX_FN chacha_core_sse2 #define SCRYPT_ROMIX_TANGLE_FN scrypt_romix_nop @@ -81,17 +93,21 @@ scrypt_getROMix() { #if defined(SCRYPT_TEST_SPEED) static size_t available_implementations() { + size_t cpuflags = detect_cpu(); size_t flags = 0; #if defined(SCRYPT_CHACHA_AVX) - flags |= cpu_avx; + if (cpuflags & cpu_avx) + flags |= cpu_avx; #endif #if defined(SCRYPT_CHACHA_SSSE3) - flags |= cpu_ssse3; + if (cpuflags & cpu_ssse3) + flags |= cpu_ssse3; #endif #if defined(SCRYPT_CHACHA_SSE2) + if (cpuflags & cpu_sse2) flags |= cpu_sse2; #endif diff --git a/scryptjane/scrypt-jane-hash_blake256.h b/scryptjane/scrypt-jane-hash_blake256.h new file mode 100644 index 000000000..dee90134e --- /dev/null +++ b/scryptjane/scrypt-jane-hash_blake256.h @@ -0,0 +1,177 @@ +#define SCRYPT_HASH "BLAKE-256" +#define SCRYPT_HASH_BLOCK_SIZE 64 +#define SCRYPT_HASH_DIGEST_SIZE 32 + +typedef uint8_t scrypt_hash_digest[SCRYPT_HASH_DIGEST_SIZE]; + +const uint8_t blake256_sigma[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3, + 11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4, + 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8, + 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13, + 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9, + 12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11, + 13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10, + 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5, + 10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13 ,0, +}; + +const uint32_t blake256_constants[16] = { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917 +}; + +typedef struct scrypt_hash_state_t { + uint32_t H[8], T[2]; + uint32_t leftover; + uint8_t buffer[SCRYPT_HASH_BLOCK_SIZE]; +} scrypt_hash_state; + +static void +blake256_blocks(scrypt_hash_state *S, const uint8_t *in, size_t blocks) { + const uint8_t *sigma, *sigma_end = blake256_sigma + (10 * 16); + uint32_t m[16], v[16], h[8], t[2]; + uint32_t i; + + for (i = 0; i < 8; i++) h[i] = S->H[i]; + for (i = 0; i < 2; i++) t[i] = S->T[i]; + + while (blocks--) { + t[0] += 512; + t[1] += (t[0] < 512) ? 1 : 0; + + for (i = 0; i < 8; i++) v[i ] = h[i]; + for (i = 0; i < 4; i++) v[i + 8] = blake256_constants[i]; + for (i = 0; i < 2; i++) v[i + 12] = blake256_constants[i+4] ^ t[0]; + for (i = 0; i < 2; i++) v[i + 14] = blake256_constants[i+6] ^ t[1]; + + for (i = 0; i < 16; i++) m[i] = U8TO32_BE(&in[i * 4]); + in += 64; + + #define G(a,b,c,d,e) \ + v[a] += (m[sigma[e+0]] ^ blake256_constants[sigma[e+1]]) + v[b]; \ + v[d] = ROTR32(v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROTR32(v[b] ^ v[c],12); \ + v[a] += (m[sigma[e+1]] ^ blake256_constants[sigma[e+0]]) + v[b]; \ + v[d] = ROTR32(v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROTR32(v[b] ^ v[c], 7); + + for (i = 0, sigma = blake256_sigma; i < 14; i++) { + G(0, 4, 8,12, 0); + G(1, 5, 9,13, 2); + G(2, 6,10,14, 4); + G(3, 7,11,15, 6); + + G(0, 5,10,15, 8); + G(1, 6,11,12,10); + G(2, 7, 8,13,12); + G(3, 4, 9,14,14); + + sigma += 16; + if (sigma == sigma_end) + sigma = blake256_sigma; + } + + #undef G + + for (i = 0; i < 8; i++) h[i] ^= (v[i] ^ v[i + 8]); + } + + for (i = 0; i < 8; i++) S->H[i] = h[i]; + for (i = 0; i < 2; i++) S->T[i] = t[i]; +} + +static void +scrypt_hash_init(scrypt_hash_state *S) { + S->H[0] = 0x6a09e667ULL; + S->H[1] = 0xbb67ae85ULL; + S->H[2] = 0x3c6ef372ULL; + S->H[3] = 0xa54ff53aULL; + S->H[4] = 0x510e527fULL; + S->H[5] = 0x9b05688cULL; + S->H[6] = 0x1f83d9abULL; + S->H[7] = 0x5be0cd19ULL; + S->T[0] = 0; + S->T[1] = 0; + S->leftover = 0; +} + +static void +scrypt_hash_update(scrypt_hash_state *S, const uint8_t *in, size_t inlen) { + size_t blocks, want; + + /* handle the previous data */ + if (S->leftover) { + want = (SCRYPT_HASH_BLOCK_SIZE - S->leftover); + want = (want < inlen) ? want : inlen; + memcpy(S->buffer + S->leftover, in, want); + S->leftover += (uint32_t)want; + if (S->leftover < SCRYPT_HASH_BLOCK_SIZE) + return; + in += want; + inlen -= want; + blake256_blocks(S, S->buffer, 1); + } + + /* handle the current data */ + blocks = (inlen & ~(SCRYPT_HASH_BLOCK_SIZE - 1)); + S->leftover = (uint32_t)(inlen - blocks); + if (blocks) { + blake256_blocks(S, in, blocks / SCRYPT_HASH_BLOCK_SIZE); + in += blocks; + } + + /* handle leftover data */ + if (S->leftover) + memcpy(S->buffer, in, S->leftover); +} + +static void +scrypt_hash_finish(scrypt_hash_state *S, uint8_t *hash) { + uint32_t th, tl, bits; + + bits = (S->leftover << 3); + tl = S->T[0] + bits; + th = S->T[1]; + if (S->leftover == 0) { + S->T[0] = (uint32_t)0 - (uint32_t)512; + S->T[1] = (uint32_t)0 - (uint32_t)1; + } else if (S->T[0] == 0) { + S->T[0] = ((uint32_t)0 - (uint32_t)512) + bits; + S->T[1] = S->T[1] - 1; + } else { + S->T[0] -= (512 - bits); + } + + S->buffer[S->leftover] = 0x80; + if (S->leftover <= 55) { + memset(S->buffer + S->leftover + 1, 0, 55 - S->leftover); + } else { + memset(S->buffer + S->leftover + 1, 0, 63 - S->leftover); + blake256_blocks(S, S->buffer, 1); + S->T[0] = (uint32_t)0 - (uint32_t)512; + S->T[1] = (uint32_t)0 - (uint32_t)1; + memset(S->buffer, 0, 56); + } + S->buffer[55] |= 1; + U32TO8_BE(S->buffer + 56, th); + U32TO8_BE(S->buffer + 60, tl); + blake256_blocks(S, S->buffer, 1); + + U32TO8_BE(&hash[ 0], S->H[0]); + U32TO8_BE(&hash[ 4], S->H[1]); + U32TO8_BE(&hash[ 8], S->H[2]); + U32TO8_BE(&hash[12], S->H[3]); + U32TO8_BE(&hash[16], S->H[4]); + U32TO8_BE(&hash[20], S->H[5]); + U32TO8_BE(&hash[24], S->H[6]); + U32TO8_BE(&hash[28], S->H[7]); +} + +static const uint8_t scrypt_test_hash_expected[SCRYPT_HASH_DIGEST_SIZE] = { + 0xcc,0xa9,0x1e,0xa9,0x20,0x97,0x37,0x40,0x17,0xc0,0xa0,0x52,0x87,0xfc,0x08,0x20, + 0x40,0xf5,0x81,0x86,0x62,0x75,0x78,0xb2,0x79,0xce,0xde,0x27,0x3c,0x7f,0x85,0xd8, +}; diff --git a/scryptjane/scrypt-jane-hash_blake512.h b/scryptjane/scrypt-jane-hash_blake512.h new file mode 100644 index 000000000..ea2a583de --- /dev/null +++ b/scryptjane/scrypt-jane-hash_blake512.h @@ -0,0 +1,181 @@ +#define SCRYPT_HASH "BLAKE-512" +#define SCRYPT_HASH_BLOCK_SIZE 128 +#define SCRYPT_HASH_DIGEST_SIZE 64 + +typedef uint8_t scrypt_hash_digest[SCRYPT_HASH_DIGEST_SIZE]; + +const uint8_t blake512_sigma[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3, + 11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4, + 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8, + 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13, + 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9, + 12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11, + 13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10, + 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5, + 10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13 ,0, +}; + +const uint64_t blake512_constants[16] = { + 0x243f6a8885a308d3ULL, 0x13198a2e03707344ULL, 0xa4093822299f31d0ULL, 0x082efa98ec4e6c89ULL, + 0x452821e638d01377ULL, 0xbe5466cf34e90c6cULL, 0xc0ac29b7c97c50ddULL, 0x3f84d5b5b5470917ULL, + 0x9216d5d98979fb1bULL, 0xd1310ba698dfb5acULL, 0x2ffd72dbd01adfb7ULL, 0xb8e1afed6a267e96ULL, + 0xba7c9045f12c7f99ULL, 0x24a19947b3916cf7ULL, 0x0801f2e2858efc16ULL, 0x636920d871574e69ULL +}; + +typedef struct scrypt_hash_state_t { + uint64_t H[8], T[2]; + uint32_t leftover; + uint8_t buffer[SCRYPT_HASH_BLOCK_SIZE]; +} scrypt_hash_state; + +static void +blake512_blocks(scrypt_hash_state *S, const uint8_t *in, size_t blocks) { + const uint8_t *sigma, *sigma_end = blake512_sigma + (10 * 16); + uint64_t m[16], v[16], h[8], t[2]; + uint32_t i; + + for (i = 0; i < 8; i++) h[i] = S->H[i]; + for (i = 0; i < 2; i++) t[i] = S->T[i]; + + while (blocks--) { + t[0] += 1024; + t[1] += (t[0] < 1024) ? 1 : 0; + + for (i = 0; i < 8; i++) v[i ] = h[i]; + for (i = 0; i < 4; i++) v[i + 8] = blake512_constants[i]; + for (i = 0; i < 2; i++) v[i + 12] = blake512_constants[i+4] ^ t[0]; + for (i = 0; i < 2; i++) v[i + 14] = blake512_constants[i+6] ^ t[1]; + + for (i = 0; i < 16; i++) m[i] = U8TO64_BE(&in[i * 8]); + in += 128; + + #define G(a,b,c,d,e) \ + v[a] += (m[sigma[e+0]] ^ blake512_constants[sigma[e+1]]) + v[b]; \ + v[d] = ROTR64(v[d] ^ v[a],32); \ + v[c] += v[d]; \ + v[b] = ROTR64(v[b] ^ v[c],25); \ + v[a] += (m[sigma[e+1]] ^ blake512_constants[sigma[e+0]]) + v[b]; \ + v[d] = ROTR64(v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROTR64(v[b] ^ v[c],11); + + for (i = 0, sigma = blake512_sigma; i < 16; i++) { + G(0, 4, 8,12, 0); + G(1, 5, 9,13, 2); + G(2, 6,10,14, 4); + G(3, 7,11,15, 6); + G(0, 5,10,15, 8); + G(1, 6,11,12,10); + G(2, 7, 8,13,12); + G(3, 4, 9,14,14); + + sigma += 16; + if (sigma == sigma_end) + sigma = blake512_sigma; + } + + #undef G + + for (i = 0; i < 8; i++) h[i] ^= (v[i] ^ v[i + 8]); + } + + for (i = 0; i < 8; i++) S->H[i] = h[i]; + for (i = 0; i < 2; i++) S->T[i] = t[i]; +} + +static void +scrypt_hash_init(scrypt_hash_state *S) { + S->H[0] = 0x6a09e667f3bcc908ULL; + S->H[1] = 0xbb67ae8584caa73bULL; + S->H[2] = 0x3c6ef372fe94f82bULL; + S->H[3] = 0xa54ff53a5f1d36f1ULL; + S->H[4] = 0x510e527fade682d1ULL; + S->H[5] = 0x9b05688c2b3e6c1fULL; + S->H[6] = 0x1f83d9abfb41bd6bULL; + S->H[7] = 0x5be0cd19137e2179ULL; + S->T[0] = 0; + S->T[1] = 0; + S->leftover = 0; +} + +static void +scrypt_hash_update(scrypt_hash_state *S, const uint8_t *in, size_t inlen) { + size_t blocks, want; + + /* handle the previous data */ + if (S->leftover) { + want = (SCRYPT_HASH_BLOCK_SIZE - S->leftover); + want = (want < inlen) ? want : inlen; + memcpy(S->buffer + S->leftover, in, want); + S->leftover += (uint32_t)want; + if (S->leftover < SCRYPT_HASH_BLOCK_SIZE) + return; + in += want; + inlen -= want; + blake512_blocks(S, S->buffer, 1); + } + + /* handle the current data */ + blocks = (inlen & ~(SCRYPT_HASH_BLOCK_SIZE - 1)); + S->leftover = (uint32_t)(inlen - blocks); + if (blocks) { + blake512_blocks(S, in, blocks / SCRYPT_HASH_BLOCK_SIZE); + in += blocks; + } + + /* handle leftover data */ + if (S->leftover) + memcpy(S->buffer, in, S->leftover); +} + +static void +scrypt_hash_finish(scrypt_hash_state *S, uint8_t *hash) { + uint64_t th, tl; + size_t bits; + + bits = (S->leftover << 3); + tl = S->T[0] + bits; + th = S->T[1]; + if (S->leftover == 0) { + S->T[0] = (uint64_t)0 - (uint64_t)1024; + S->T[1] = (uint64_t)0 - (uint64_t)1; + } else if (S->T[0] == 0) { + S->T[0] = ((uint64_t)0 - (uint64_t)1024) + bits; + S->T[1] = S->T[1] - 1; + } else { + S->T[0] -= (1024 - bits); + } + + S->buffer[S->leftover] = 0x80; + if (S->leftover <= 111) { + memset(S->buffer + S->leftover + 1, 0, 111 - S->leftover); + } else { + memset(S->buffer + S->leftover + 1, 0, 127 - S->leftover); + blake512_blocks(S, S->buffer, 1); + S->T[0] = (uint64_t)0 - (uint64_t)1024; + S->T[1] = (uint64_t)0 - (uint64_t)1; + memset(S->buffer, 0, 112); + } + S->buffer[111] |= 1; + U64TO8_BE(S->buffer + 112, th); + U64TO8_BE(S->buffer + 120, tl); + blake512_blocks(S, S->buffer, 1); + + U64TO8_BE(&hash[ 0], S->H[0]); + U64TO8_BE(&hash[ 8], S->H[1]); + U64TO8_BE(&hash[16], S->H[2]); + U64TO8_BE(&hash[24], S->H[3]); + U64TO8_BE(&hash[32], S->H[4]); + U64TO8_BE(&hash[40], S->H[5]); + U64TO8_BE(&hash[48], S->H[6]); + U64TO8_BE(&hash[56], S->H[7]); +} + +static const uint8_t scrypt_test_hash_expected[SCRYPT_HASH_DIGEST_SIZE] = { + 0x2f,0x9d,0x5b,0xbe,0x24,0x0d,0x63,0xd3,0xa0,0xac,0x4f,0xd3,0x01,0xc0,0x23,0x6f, + 0x6d,0xdf,0x6e,0xfb,0x60,0x6f,0xa0,0x74,0xdf,0x9f,0x25,0x65,0xb6,0x11,0x0a,0x83, + 0x23,0x96,0xba,0x91,0x68,0x4b,0x85,0x15,0x13,0x54,0xba,0x19,0xf3,0x2c,0x5a,0x4a, + 0x1f,0x78,0x31,0x02,0xc9,0x1e,0x56,0xc4,0x54,0xca,0xf9,0x8f,0x2c,0x7f,0x85,0xac +}; diff --git a/scryptjane/scrypt-jane-hash_sha512.h b/scryptjane/scrypt-jane-hash_sha512.h new file mode 100644 index 000000000..3e3997d00 --- /dev/null +++ b/scryptjane/scrypt-jane-hash_sha512.h @@ -0,0 +1,152 @@ +#define SCRYPT_HASH "SHA-2-512" +#define SCRYPT_HASH_BLOCK_SIZE 128 +#define SCRYPT_HASH_DIGEST_SIZE 64 + +typedef uint8_t scrypt_hash_digest[SCRYPT_HASH_DIGEST_SIZE]; + +typedef struct scrypt_hash_state_t { + uint64_t H[8]; + uint64_t T[2]; + uint32_t leftover; + uint8_t buffer[SCRYPT_HASH_BLOCK_SIZE]; +} scrypt_hash_state; + +static const uint64_t sha512_constants[80] = { + 0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull, + 0x3956c25bf348b538ull, 0x59f111f1b605d019ull, 0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, + 0xd807aa98a3030242ull, 0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull, + 0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull, 0xc19bf174cf692694ull, + 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull, 0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, + 0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull, + 0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full, 0xbf597fc7beef0ee4ull, + 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull, 0x06ca6351e003826full, 0x142929670a0e6e70ull, + 0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull, + 0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull, 0x92722c851482353bull, + 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull, 0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, + 0xd192e819d6ef5218ull, 0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull, + 0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull, + 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull, 0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, + 0x748f82ee5defb2fcull, 0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull, + 0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull, + 0xca273eceea26619cull, 0xd186b8c721c0c207ull, 0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, + 0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull, + 0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull, 0x431d67c49c100d4cull, + 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull, 0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull +}; + +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S0(x) (ROTR64(x, 28) ^ ROTR64(x, 34) ^ ROTR64(x, 39)) +#define S1(x) (ROTR64(x, 14) ^ ROTR64(x, 18) ^ ROTR64(x, 41)) +#define G0(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ (x >> 7)) +#define G1(x) (ROTR64(x, 19) ^ ROTR64(x, 61) ^ (x >> 6)) +#define W0(in,i) (U8TO64_BE(&in[i * 8])) +#define W1(i) (G1(w[i - 2]) + w[i - 7] + G0(w[i - 15]) + w[i - 16]) +#define STEP(i) \ + t1 = S0(r[0]) + Maj(r[0], r[1], r[2]); \ + t0 = r[7] + S1(r[4]) + Ch(r[4], r[5], r[6]) + sha512_constants[i] + w[i]; \ + r[7] = r[6]; \ + r[6] = r[5]; \ + r[5] = r[4]; \ + r[4] = r[3] + t0; \ + r[3] = r[2]; \ + r[2] = r[1]; \ + r[1] = r[0]; \ + r[0] = t0 + t1; + +static void +sha512_blocks(scrypt_hash_state *S, const uint8_t *in, size_t blocks) { + uint64_t r[8], w[80], t0, t1; + size_t i; + + for (i = 0; i < 8; i++) r[i] = S->H[i]; + + while (blocks--) { + for (i = 0; i < 16; i++) { w[i] = W0(in, i); } + for (i = 16; i < 80; i++) { w[i] = W1(i); } + for (i = 0; i < 80; i++) { STEP(i); } + for (i = 0; i < 8; i++) { r[i] += S->H[i]; S->H[i] = r[i]; } + S->T[0] += SCRYPT_HASH_BLOCK_SIZE * 8; + S->T[1] += (!S->T[0]) ? 1 : 0; + in += SCRYPT_HASH_BLOCK_SIZE; + } +} + +static void +scrypt_hash_init(scrypt_hash_state *S) { + S->H[0] = 0x6a09e667f3bcc908ull; + S->H[1] = 0xbb67ae8584caa73bull; + S->H[2] = 0x3c6ef372fe94f82bull; + S->H[3] = 0xa54ff53a5f1d36f1ull; + S->H[4] = 0x510e527fade682d1ull; + S->H[5] = 0x9b05688c2b3e6c1full; + S->H[6] = 0x1f83d9abfb41bd6bull; + S->H[7] = 0x5be0cd19137e2179ull; + S->T[0] = 0; + S->T[1] = 0; + S->leftover = 0; +} + +static void +scrypt_hash_update(scrypt_hash_state *S, const uint8_t *in, size_t inlen) { + size_t blocks, want; + + /* handle the previous data */ + if (S->leftover) { + want = (SCRYPT_HASH_BLOCK_SIZE - S->leftover); + want = (want < inlen) ? want : inlen; + memcpy(S->buffer + S->leftover, in, want); + S->leftover += (uint32_t)want; + if (S->leftover < SCRYPT_HASH_BLOCK_SIZE) + return; + in += want; + inlen -= want; + sha512_blocks(S, S->buffer, 1); + } + + /* handle the current data */ + blocks = (inlen & ~(SCRYPT_HASH_BLOCK_SIZE - 1)); + S->leftover = (uint32_t)(inlen - blocks); + if (blocks) { + sha512_blocks(S, in, blocks / SCRYPT_HASH_BLOCK_SIZE); + in += blocks; + } + + /* handle leftover data */ + if (S->leftover) + memcpy(S->buffer, in, S->leftover); +} + +static void +scrypt_hash_finish(scrypt_hash_state *S, uint8_t *hash) { + uint64_t t0 = S->T[0] + (S->leftover * 8), t1 = S->T[1]; + + S->buffer[S->leftover] = 0x80; + if (S->leftover <= 111) { + memset(S->buffer + S->leftover + 1, 0, 111 - S->leftover); + } else { + memset(S->buffer + S->leftover + 1, 0, 127 - S->leftover); + sha512_blocks(S, S->buffer, 1); + memset(S->buffer, 0, 112); + } + + U64TO8_BE(S->buffer + 112, t1); + U64TO8_BE(S->buffer + 120, t0); + sha512_blocks(S, S->buffer, 1); + + U64TO8_BE(&hash[ 0], S->H[0]); + U64TO8_BE(&hash[ 8], S->H[1]); + U64TO8_BE(&hash[16], S->H[2]); + U64TO8_BE(&hash[24], S->H[3]); + U64TO8_BE(&hash[32], S->H[4]); + U64TO8_BE(&hash[40], S->H[5]); + U64TO8_BE(&hash[48], S->H[6]); + U64TO8_BE(&hash[56], S->H[7]); +} + +static const uint8_t scrypt_test_hash_expected[SCRYPT_HASH_DIGEST_SIZE] = { + 0xba,0xc3,0x80,0x2b,0x24,0x56,0x95,0x1f,0x19,0x7c,0xa2,0xd3,0x72,0x7c,0x9a,0x4d, + 0x1d,0x50,0x3a,0xa9,0x12,0x27,0xd8,0xe1,0xbe,0x76,0x53,0x87,0x5a,0x1e,0x82,0xec, + 0xc8,0xe1,0x6b,0x87,0xd0,0xb5,0x25,0x7e,0xe8,0x1e,0xd7,0x58,0xc6,0x2d,0xc2,0x9c, + 0x06,0x31,0x8f,0x5b,0x57,0x8e,0x76,0xba,0xd5,0xf6,0xec,0xfe,0x85,0x1f,0x34,0x0c, +}; diff --git a/scryptjane/scrypt-jane-hash_skein512.h b/scryptjane/scrypt-jane-hash_skein512.h new file mode 100644 index 000000000..a95d46b17 --- /dev/null +++ b/scryptjane/scrypt-jane-hash_skein512.h @@ -0,0 +1,188 @@ +#define SCRYPT_HASH "Skein-512" +#define SCRYPT_HASH_BLOCK_SIZE 64 +#define SCRYPT_HASH_DIGEST_SIZE 64 + +typedef uint8_t scrypt_hash_digest[SCRYPT_HASH_DIGEST_SIZE]; + +typedef struct scrypt_hash_state_t { + uint64_t X[8], T[2]; + uint32_t leftover; + uint8_t buffer[SCRYPT_HASH_BLOCK_SIZE]; +} scrypt_hash_state; + +#include + +static void +skein512_blocks(scrypt_hash_state *S, const uint8_t *in, size_t blocks, size_t add) { + uint64_t X[8], key[8], Xt[9+18], T[3+1]; + size_t r; + + while (blocks--) { + T[0] = S->T[0] + add; + T[1] = S->T[1]; + T[2] = T[0] ^ T[1]; + key[0] = U8TO64_LE(in + 0); Xt[0] = S->X[0]; X[0] = key[0] + Xt[0]; + key[1] = U8TO64_LE(in + 8); Xt[1] = S->X[1]; X[1] = key[1] + Xt[1]; + key[2] = U8TO64_LE(in + 16); Xt[2] = S->X[2]; X[2] = key[2] + Xt[2]; + key[3] = U8TO64_LE(in + 24); Xt[3] = S->X[3]; X[3] = key[3] + Xt[3]; + key[4] = U8TO64_LE(in + 32); Xt[4] = S->X[4]; X[4] = key[4] + Xt[4]; + key[5] = U8TO64_LE(in + 40); Xt[5] = S->X[5]; X[5] = key[5] + Xt[5] + T[0]; + key[6] = U8TO64_LE(in + 48); Xt[6] = S->X[6]; X[6] = key[6] + Xt[6] + T[1]; + key[7] = U8TO64_LE(in + 56); Xt[7] = S->X[7]; X[7] = key[7] + Xt[7]; + Xt[8] = 0x1BD11BDAA9FC1A22ull ^ Xt[0] ^ Xt[1] ^ Xt[2] ^ Xt[3] ^ Xt[4] ^ Xt[5] ^ Xt[6] ^ Xt[7]; + in += SCRYPT_HASH_BLOCK_SIZE; + + for (r = 0; r < 18; r++) + Xt[r + 9] = Xt[r + 0]; + + for (r = 0; r < 18; r += 2) { + X[0] += X[1]; X[1] = ROTL64(X[1], 46) ^ X[0]; + X[2] += X[3]; X[3] = ROTL64(X[3], 36) ^ X[2]; + X[4] += X[5]; X[5] = ROTL64(X[5], 19) ^ X[4]; + X[6] += X[7]; X[7] = ROTL64(X[7], 37) ^ X[6]; + X[2] += X[1]; X[1] = ROTL64(X[1], 33) ^ X[2]; + X[0] += X[3]; X[3] = ROTL64(X[3], 42) ^ X[0]; + X[6] += X[5]; X[5] = ROTL64(X[5], 14) ^ X[6]; + X[4] += X[7]; X[7] = ROTL64(X[7], 27) ^ X[4]; + X[4] += X[1]; X[1] = ROTL64(X[1], 17) ^ X[4]; + X[6] += X[3]; X[3] = ROTL64(X[3], 49) ^ X[6]; + X[0] += X[5]; X[5] = ROTL64(X[5], 36) ^ X[0]; + X[2] += X[7]; X[7] = ROTL64(X[7], 39) ^ X[2]; + X[6] += X[1]; X[1] = ROTL64(X[1], 44) ^ X[6]; + X[4] += X[3]; X[3] = ROTL64(X[3], 56) ^ X[4]; + X[2] += X[5]; X[5] = ROTL64(X[5], 54) ^ X[2]; + X[0] += X[7]; X[7] = ROTL64(X[7], 9) ^ X[0]; + + X[0] += Xt[r + 1]; + X[1] += Xt[r + 2]; + X[2] += Xt[r + 3]; + X[3] += Xt[r + 4]; + X[4] += Xt[r + 5]; + X[5] += Xt[r + 6] + T[1]; + X[6] += Xt[r + 7] + T[2]; + X[7] += Xt[r + 8] + r + 1; + + T[3] = T[0]; + T[0] = T[1]; + T[1] = T[2]; + T[2] = T[3]; + + X[0] += X[1]; X[1] = ROTL64(X[1], 39) ^ X[0]; + X[2] += X[3]; X[3] = ROTL64(X[3], 30) ^ X[2]; + X[4] += X[5]; X[5] = ROTL64(X[5], 34) ^ X[4]; + X[6] += X[7]; X[7] = ROTL64(X[7], 24) ^ X[6]; + X[2] += X[1]; X[1] = ROTL64(X[1], 13) ^ X[2]; + X[0] += X[3]; X[3] = ROTL64(X[3], 17) ^ X[0]; + X[6] += X[5]; X[5] = ROTL64(X[5], 10) ^ X[6]; + X[4] += X[7]; X[7] = ROTL64(X[7], 50) ^ X[4]; + X[4] += X[1]; X[1] = ROTL64(X[1], 25) ^ X[4]; + X[6] += X[3]; X[3] = ROTL64(X[3], 29) ^ X[6]; + X[0] += X[5]; X[5] = ROTL64(X[5], 39) ^ X[0]; + X[2] += X[7]; X[7] = ROTL64(X[7], 43) ^ X[2]; + X[6] += X[1]; X[1] = ROTL64(X[1], 8) ^ X[6]; + X[4] += X[3]; X[3] = ROTL64(X[3], 22) ^ X[4]; + X[2] += X[5]; X[5] = ROTL64(X[5], 56) ^ X[2]; + X[0] += X[7]; X[7] = ROTL64(X[7], 35) ^ X[0]; + + X[0] += Xt[r + 2]; + X[1] += Xt[r + 3]; + X[2] += Xt[r + 4]; + X[3] += Xt[r + 5]; + X[4] += Xt[r + 6]; + X[5] += Xt[r + 7] + T[1]; + X[6] += Xt[r + 8] + T[2]; + X[7] += Xt[r + 9] + r + 2; + + T[3] = T[0]; + T[0] = T[1]; + T[1] = T[2]; + T[2] = T[3]; + } + + S->X[0] = key[0] ^ X[0]; + S->X[1] = key[1] ^ X[1]; + S->X[2] = key[2] ^ X[2]; + S->X[3] = key[3] ^ X[3]; + S->X[4] = key[4] ^ X[4]; + S->X[5] = key[5] ^ X[5]; + S->X[6] = key[6] ^ X[6]; + S->X[7] = key[7] ^ X[7]; + + S->T[0] = T[0]; + S->T[1] = T[1] & ~0x4000000000000000ull; + } +} + +static void +scrypt_hash_init(scrypt_hash_state *S) { + S->X[0] = 0x4903ADFF749C51CEull; + S->X[1] = 0x0D95DE399746DF03ull; + S->X[2] = 0x8FD1934127C79BCEull; + S->X[3] = 0x9A255629FF352CB1ull; + S->X[4] = 0x5DB62599DF6CA7B0ull; + S->X[5] = 0xEABE394CA9D5C3F4ull; + S->X[6] = 0x991112C71A75B523ull; + S->X[7] = 0xAE18A40B660FCC33ull; + S->T[0] = 0x0000000000000000ull; + S->T[1] = 0x7000000000000000ull; + S->leftover = 0; +} + +static void +scrypt_hash_update(scrypt_hash_state *S, const uint8_t *in, size_t inlen) { + size_t blocks, want; + + /* skein processes the final <=64 bytes raw, so we can only update if there are at least 64+1 bytes available */ + if ((S->leftover + inlen) > SCRYPT_HASH_BLOCK_SIZE) { + /* handle the previous data, we know there is enough for at least one block */ + if (S->leftover) { + want = (SCRYPT_HASH_BLOCK_SIZE - S->leftover); + memcpy(S->buffer + S->leftover, in, want); + in += want; + inlen -= want; + S->leftover = 0; + skein512_blocks(S, S->buffer, 1, SCRYPT_HASH_BLOCK_SIZE); + } + + /* handle the current data if there's more than one block */ + if (inlen > SCRYPT_HASH_BLOCK_SIZE) { + blocks = ((inlen - 1) & ~(SCRYPT_HASH_BLOCK_SIZE - 1)); + skein512_blocks(S, in, blocks / SCRYPT_HASH_BLOCK_SIZE, SCRYPT_HASH_BLOCK_SIZE); + inlen -= blocks; + in += blocks; + } + } + + /* handle leftover data */ + memcpy(S->buffer + S->leftover, in, inlen); + S->leftover += inlen; +} + +static void +scrypt_hash_finish(scrypt_hash_state *S, uint8_t *hash) { + memset(S->buffer + S->leftover, 0, SCRYPT_HASH_BLOCK_SIZE - S->leftover); + S->T[1] |= 0x8000000000000000ull; + skein512_blocks(S, S->buffer, 1, S->leftover); + + memset(S->buffer, 0, SCRYPT_HASH_BLOCK_SIZE); + S->T[0] = 0; + S->T[1] = 0xff00000000000000ull; + skein512_blocks(S, S->buffer, 1, 8); + + U64TO8_LE(&hash[ 0], S->X[0]); + U64TO8_LE(&hash[ 8], S->X[1]); + U64TO8_LE(&hash[16], S->X[2]); + U64TO8_LE(&hash[24], S->X[3]); + U64TO8_LE(&hash[32], S->X[4]); + U64TO8_LE(&hash[40], S->X[5]); + U64TO8_LE(&hash[48], S->X[6]); + U64TO8_LE(&hash[56], S->X[7]); +} + + +static const uint8_t scrypt_test_hash_expected[SCRYPT_HASH_DIGEST_SIZE] = { + 0x4d,0x52,0x29,0xff,0x10,0xbc,0xd2,0x62,0xd1,0x61,0x83,0xc8,0xe6,0xf0,0x83,0xc4, + 0x9f,0xf5,0x6a,0x42,0x75,0x2a,0x26,0x4e,0xf0,0x28,0x72,0x28,0x47,0xe8,0x23,0xdf, + 0x1e,0x64,0xf1,0x51,0x38,0x35,0x9d,0xc2,0x83,0xfc,0x35,0x4e,0xc0,0x52,0x5f,0x41, + 0x6a,0x0b,0x7d,0xf5,0xce,0x98,0xde,0x6f,0x36,0xd8,0x51,0x15,0x78,0x78,0x93,0x67, +}; diff --git a/scryptjane/scrypt-jane-mix_chacha-avx.h b/scryptjane/scrypt-jane-mix_chacha-avx.h index 50d6e2d2a..17559d88a 100644 --- a/scryptjane/scrypt-jane-mix_chacha-avx.h +++ b/scryptjane/scrypt-jane-mix_chacha-avx.h @@ -20,8 +20,28 @@ asm_naked_fn(scrypt_ChunkMix_avx) a2(shl edx,6) a2(lea ecx,[edx-64]) a2(and eax, eax) - a2(vmovdqa xmm4,[ssse3_rotl16_32bit]) - a2(vmovdqa xmm5,[ssse3_rotl8_32bit]) + a2(mov ebx, 0x01000302) + a2(vmovd xmm4, ebx) + a2(mov ebx, 0x05040706) + a2(vmovd xmm0, ebx) + a2(mov ebx, 0x09080b0a) + a2(vmovd xmm1, ebx) + a2(mov ebx, 0x0d0c0f0e) + a2(vmovd xmm2, ebx) + a2(mov ebx, 0x02010003) + a2(vmovd xmm5, ebx) + a2(mov ebx, 0x06050407) + a2(vmovd xmm3, ebx) + a2(mov ebx, 0x0a09080b) + a2(vmovd xmm6, ebx) + a2(mov ebx, 0x0e0d0c0f) + a2(vmovd xmm7, ebx) + a3(vpunpckldq xmm4, xmm4, xmm0) + a3(vpunpckldq xmm5, xmm5, xmm3) + a3(vpunpckldq xmm1, xmm1, xmm2) + a3(vpunpckldq xmm6, xmm6, xmm7) + a3(vpunpcklqdq xmm4, xmm4, xmm1) + a3(vpunpcklqdq xmm5, xmm5, xmm6) a2(vmovdqa xmm0,[ecx+esi+0]) a2(vmovdqa xmm1,[ecx+esi+16]) a2(vmovdqa xmm2,[ecx+esi+32]) @@ -114,7 +134,7 @@ asm_naked_fn(scrypt_ChunkMix_avx) a1(pop esi) a1(pop edi) a1(pop ebx) - a1(ret 16) + aret(16) asm_naked_fn_end(scrypt_ChunkMix_avx) #endif @@ -134,12 +154,20 @@ asm_naked_fn(scrypt_ChunkMix_avx) a2(lea rax,[rsi+r9]) a2(lea r9,[rdx+r9]) a2(and rdx, rdx) - a2(vmovdqa xmm4,[ssse3_rotl16_32bit]) - a2(vmovdqa xmm5,[ssse3_rotl8_32bit]) a2(vmovdqa xmm0,[rax+0]) a2(vmovdqa xmm1,[rax+16]) a2(vmovdqa xmm2,[rax+32]) a2(vmovdqa xmm3,[rax+48]) + a2(mov r8, 0x0504070601000302) + a2(mov rax, 0x0d0c0f0e09080b0a) + a2(movq xmm4, r8) + a2(movq xmm6, rax) + a2(mov r8, 0x0605040702010003) + a2(mov rax, 0x0e0d0c0f0a09080b) + a2(movq xmm5, r8) + a2(movq xmm7, rax) + a3(vpunpcklqdq xmm4, xmm4, xmm6) + a3(vpunpcklqdq xmm5, xmm5, xmm7) a1(jz scrypt_ChunkMix_avx_no_xor1) a3(vpxor xmm0,xmm0,[r9+0]) a3(vpxor xmm1,xmm1,[r9+16]) @@ -283,8 +311,9 @@ scrypt_ChunkMix_avx(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]* x3 = _mm_shuffle_epi8(x3, x4); x2 = _mm_add_epi32(x2, x3); x1 = _mm_xor_si128(x1, x2); - x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 12), _mm_srli_epi32(x6, 20)); + x6 = _mm_srli_epi32(x1, 20); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, x6); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x3 = _mm_shuffle_epi8(x3, x5); @@ -293,15 +322,17 @@ scrypt_ChunkMix_avx(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]* x3 = _mm_shuffle_epi32(x3, 0x4e); x1 = _mm_xor_si128(x1, x2); x2 = _mm_shuffle_epi32(x2, 0x39); - x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 7), _mm_srli_epi32(x6, 25)); + x6 = _mm_srli_epi32(x1, 25); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, x6); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x3 = _mm_shuffle_epi8(x3, x4); x2 = _mm_add_epi32(x2, x3); x1 = _mm_xor_si128(x1, x2); - x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 12), _mm_srli_epi32(x6, 20)); + x6 = _mm_srli_epi32(x1, 20); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, x6); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x3 = _mm_shuffle_epi8(x3, x5); @@ -310,8 +341,201 @@ scrypt_ChunkMix_avx(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]* x3 = _mm_shuffle_epi32(x3, 0x4e); x1 = _mm_xor_si128(x1, x2); x2 = _mm_shuffle_epi32(x2, 0x93); - x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 7), _mm_srli_epi32(x6, 25)); + x6 = _mm_srli_epi32(x1, 25); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, x6); + } + + x0 = _mm_add_epi32(x0, t0); + x1 = _mm_add_epi32(x1, t1); + x2 = _mm_add_epi32(x2, t2); + x3 = _mm_add_epi32(x3, t3); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + } +} + +/* + * Special version with r = 1 and no XORing + * - mikaelh + */ +static void NOINLINE +scrypt_ChunkMix_avx_1(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]*/) { + const uint32_t r = 1; + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x6,t0,t1,t2,t3; + const xmmi x4 = *(xmmi *)&ssse3_rotl16_32bit, x5 = *(xmmi *)&ssse3_rotl8_32bit; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + + for (rounds = 8; rounds; rounds -= 2) { + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = _mm_srli_epi32(x1, 20); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, x6); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x93); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x39); + x6 = _mm_srli_epi32(x1, 25); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, x6); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = _mm_srli_epi32(x1, 20); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, x6); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x39); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x93); + x6 = _mm_srli_epi32(x1, 25); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, x6); + } + + x0 = _mm_add_epi32(x0, t0); + x1 = _mm_add_epi32(x1, t1); + x2 = _mm_add_epi32(x2, t2); + x3 = _mm_add_epi32(x3, t3); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + } +} + +/* + * Special version with r = 1 and unconditional XORing + * - mikaelh + */ +static void NOINLINE +scrypt_ChunkMix_avx_1_xor(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]*/, uint32_t *Bxor/*[chunkBytes]*/) { + const uint32_t r = 1; + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x6,t0,t1,t2,t3; + const xmmi x4 = *(xmmi *)&ssse3_rotl16_32bit, x5 = *(xmmi *)&ssse3_rotl8_32bit; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + + xmmp = (xmmi *)scrypt_block(Bxor, blocksPerChunk - 1); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + xmmp = (xmmi *)scrypt_block(Bxor, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + + for (rounds = 8; rounds; rounds -= 2) { + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = _mm_srli_epi32(x1, 20); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, x6); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x93); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x39); + x6 = _mm_srli_epi32(x1, 25); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, x6); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = _mm_srli_epi32(x1, 20); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, x6); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x39); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x93); + x6 = _mm_srli_epi32(x1, 25); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, x6); } x0 = _mm_add_epi32(x0, t0); diff --git a/scryptjane/scrypt-jane-mix_chacha-sse2.h b/scryptjane/scrypt-jane-mix_chacha-sse2.h index d2192c8f9..8f79decde 100644 --- a/scryptjane/scrypt-jane-mix_chacha-sse2.h +++ b/scryptjane/scrypt-jane-mix_chacha-sse2.h @@ -128,7 +128,7 @@ asm_naked_fn(scrypt_ChunkMix_sse2) a1(pop esi) a1(pop edi) a1(pop ebx) - a1(ret 16) + aret(16) asm_naked_fn_end(scrypt_ChunkMix_sse2) #endif @@ -308,41 +308,255 @@ scrypt_ChunkMix_sse2(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes] x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x4 = x3; - x3 = _mm_or_si128(_mm_slli_epi32(x3, 16), _mm_srli_epi32(x4, 16)); + x3 = _mm_slli_epi32(x3, 16); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 16)); x2 = _mm_add_epi32(x2, x3); x1 = _mm_xor_si128(x1, x2); x4 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 12), _mm_srli_epi32(x4, 20)); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 20)); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x4 = x3; - x3 = _mm_or_si128(_mm_slli_epi32(x3, 8), _mm_srli_epi32(x4, 24)); + x3 = _mm_slli_epi32(x3, 8); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 24)); x0 = _mm_shuffle_epi32(x0, 0x93); x2 = _mm_add_epi32(x2, x3); x3 = _mm_shuffle_epi32(x3, 0x4e); x1 = _mm_xor_si128(x1, x2); x2 = _mm_shuffle_epi32(x2, 0x39); x4 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 7), _mm_srli_epi32(x4, 25)); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 25)); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x4 = x3; - x3 = _mm_or_si128(_mm_slli_epi32(x3, 16), _mm_srli_epi32(x4, 16)); + x3 = _mm_slli_epi32(x3, 16); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 16)); x2 = _mm_add_epi32(x2, x3); x1 = _mm_xor_si128(x1, x2); x4 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 12), _mm_srli_epi32(x4, 20)); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 20)); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x4 = x3; - x3 = _mm_or_si128(_mm_slli_epi32(x3, 8), _mm_srli_epi32(x4, 24)); + x3 = _mm_slli_epi32(x3, 8); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 24)); x0 = _mm_shuffle_epi32(x0, 0x39); x2 = _mm_add_epi32(x2, x3); x3 = _mm_shuffle_epi32(x3, 0x4e); x1 = _mm_xor_si128(x1, x2); x2 = _mm_shuffle_epi32(x2, 0x93); x4 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 7), _mm_srli_epi32(x4, 25)); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 25)); + } + + x0 = _mm_add_epi32(x0, t0); + x1 = _mm_add_epi32(x1, t1); + x2 = _mm_add_epi32(x2, t2); + x3 = _mm_add_epi32(x3, t3); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + } +} + +/* + * Special version with r = 1 and no XORing + * - mikaelh + */ +static void NOINLINE +scrypt_ChunkMix_sse2_1(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]*/) { + const uint32_t r = 1; + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x4,t0,t1,t2,t3; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + + for (rounds = 8; rounds; rounds -= 2) { + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 16); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 16)); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x4 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 8); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 24)); + x0 = _mm_shuffle_epi32(x0, 0x93); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x39); + x4 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 25)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 16); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 16)); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x4 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 8); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 24)); + x0 = _mm_shuffle_epi32(x0, 0x39); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x93); + x4 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 25)); + } + + x0 = _mm_add_epi32(x0, t0); + x1 = _mm_add_epi32(x1, t1); + x2 = _mm_add_epi32(x2, t2); + x3 = _mm_add_epi32(x3, t3); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + } +} + +/* + * Special version with r = 1 and unconditional XORing + * - mikaelh + */ +static void NOINLINE +scrypt_ChunkMix_sse2_1_xor(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]*/, uint32_t *Bxor/*[chunkBytes]*/) { + const uint32_t r = 1; + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x4,t0,t1,t2,t3; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + + xmmp = (xmmi *)scrypt_block(Bxor, blocksPerChunk - 1); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + xmmp = (xmmi *)scrypt_block(Bxor, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + + for (rounds = 8; rounds; rounds -= 2) { + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 16); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 16)); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x4 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 8); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 24)); + x0 = _mm_shuffle_epi32(x0, 0x93); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x39); + x4 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 25)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 16); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 16)); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x4 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x4 = x3; + x3 = _mm_slli_epi32(x3, 8); + x3 = _mm_or_si128(x3, _mm_srli_epi32(x4, 24)); + x0 = _mm_shuffle_epi32(x0, 0x39); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x93); + x4 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x4, 25)); } x0 = _mm_add_epi32(x0, t0); diff --git a/scryptjane/scrypt-jane-mix_chacha-ssse3.h b/scryptjane/scrypt-jane-mix_chacha-ssse3.h index b25e35672..6a80cac5b 100644 --- a/scryptjane/scrypt-jane-mix_chacha-ssse3.h +++ b/scryptjane/scrypt-jane-mix_chacha-ssse3.h @@ -20,8 +20,28 @@ asm_naked_fn(scrypt_ChunkMix_ssse3) a2(shl edx,6) a2(lea ecx,[edx-64]) a2(and eax, eax) - a2(movdqa xmm4,[ssse3_rotl16_32bit]) - a2(movdqa xmm5,[ssse3_rotl8_32bit]) + a2(mov ebx, 0x01000302) + a2(movd xmm4, ebx) + a2(mov ebx, 0x05040706) + a2(movd xmm0, ebx) + a2(mov ebx, 0x09080b0a) + a2(movd xmm1, ebx) + a2(mov ebx, 0x0d0c0f0e) + a2(movd xmm2, ebx) + a2(mov ebx, 0x02010003) + a2(movd xmm5, ebx) + a2(mov ebx, 0x06050407) + a2(movd xmm3, ebx) + a2(mov ebx, 0x0a09080b) + a2(movd xmm6, ebx) + a2(mov ebx, 0x0e0d0c0f) + a2(movd xmm7, ebx) + a2(punpckldq xmm4, xmm0) + a2(punpckldq xmm5, xmm3) + a2(punpckldq xmm1, xmm2) + a2(punpckldq xmm6, xmm7) + a2(punpcklqdq xmm4, xmm1) + a2(punpcklqdq xmm5, xmm6) a2(movdqa xmm0,[ecx+esi+0]) a2(movdqa xmm1,[ecx+esi+16]) a2(movdqa xmm2,[ecx+esi+32]) @@ -118,7 +138,7 @@ asm_naked_fn(scrypt_ChunkMix_ssse3) a1(pop esi) a1(pop edi) a1(pop ebx) - a1(ret 16) + aret(16) asm_naked_fn_end(scrypt_ChunkMix_ssse3) #endif @@ -138,12 +158,20 @@ asm_naked_fn(scrypt_ChunkMix_ssse3) a2(lea rax,[rsi+r9]) a2(lea r9,[rdx+r9]) a2(and rdx, rdx) - a2(movdqa xmm4,[ssse3_rotl16_32bit]) - a2(movdqa xmm5,[ssse3_rotl8_32bit]) a2(movdqa xmm0,[rax+0]) a2(movdqa xmm1,[rax+16]) a2(movdqa xmm2,[rax+32]) a2(movdqa xmm3,[rax+48]) + a2(mov r8, 0x0504070601000302) + a2(mov rax, 0x0d0c0f0e09080b0a) + a2(movq xmm4, r8) + a2(movq xmm6, rax) + a2(mov r8, 0x0605040702010003) + a2(mov rax, 0x0e0d0c0f0a09080b) + a2(movq xmm5, r8) + a2(movq xmm7, rax) + a2(punpcklqdq xmm4, xmm6) + a2(punpcklqdq xmm5, xmm7) a1(jz scrypt_ChunkMix_ssse3_no_xor1) a2(pxor xmm0,[r9+0]) a2(pxor xmm1,[r9+16]) @@ -292,7 +320,8 @@ scrypt_ChunkMix_ssse3(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes x2 = _mm_add_epi32(x2, x3); x1 = _mm_xor_si128(x1, x2); x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 12), _mm_srli_epi32(x6, 20)); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 20)); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x3 = _mm_shuffle_epi8(x3, x5); @@ -302,14 +331,16 @@ scrypt_ChunkMix_ssse3(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes x1 = _mm_xor_si128(x1, x2); x2 = _mm_shuffle_epi32(x2, 0x39); x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 7), _mm_srli_epi32(x6, 25)); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 25)); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x3 = _mm_shuffle_epi8(x3, x4); x2 = _mm_add_epi32(x2, x3); x1 = _mm_xor_si128(x1, x2); x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 12), _mm_srli_epi32(x6, 20)); + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 20)); x0 = _mm_add_epi32(x0, x1); x3 = _mm_xor_si128(x3, x0); x3 = _mm_shuffle_epi8(x3, x5); @@ -319,7 +350,200 @@ scrypt_ChunkMix_ssse3(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes x1 = _mm_xor_si128(x1, x2); x2 = _mm_shuffle_epi32(x2, 0x93); x6 = x1; - x1 = _mm_or_si128(_mm_slli_epi32(x1, 7), _mm_srli_epi32(x6, 25)); + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 25)); + } + + x0 = _mm_add_epi32(x0, t0); + x1 = _mm_add_epi32(x1, t1); + x2 = _mm_add_epi32(x2, t2); + x3 = _mm_add_epi32(x3, t3); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + } +} + +/* + * Special version with r = 1 and no XORing + * - mikaelh + */ +static void NOINLINE +scrypt_ChunkMix_ssse3_1(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]*/) { + const uint32_t r = 1; + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x6,t0,t1,t2,t3; + const xmmi x4 = *(xmmi *)&ssse3_rotl16_32bit, x5 = *(xmmi *)&ssse3_rotl8_32bit; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + + for (rounds = 8; rounds; rounds -= 2) { + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x93); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x39); + x6 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 25)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x39); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x93); + x6 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 25)); + } + + x0 = _mm_add_epi32(x0, t0); + x1 = _mm_add_epi32(x1, t1); + x2 = _mm_add_epi32(x2, t2); + x3 = _mm_add_epi32(x3, t3); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + } +} + +/* + * Special version with r = 1 and unconditional XORing + * - mikaelh + */ +static void NOINLINE +scrypt_ChunkMix_ssse3_1_xor(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes]*/, uint32_t *Bxor/*[chunkBytes]*/) { + const uint32_t r = 1; + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x6,t0,t1,t2,t3; + const xmmi x4 = *(xmmi *)&ssse3_rotl16_32bit, x5 = *(xmmi *)&ssse3_rotl8_32bit; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + + xmmp = (xmmi *)scrypt_block(Bxor, blocksPerChunk - 1); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + xmmp = (xmmi *)scrypt_block(Bxor, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + + for (rounds = 8; rounds; rounds -= 2) { + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x93); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x39); + x6 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 25)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x4); + x2 = _mm_add_epi32(x2, x3); + x1 = _mm_xor_si128(x1, x2); + x6 = x1; + x1 = _mm_slli_epi32(x1, 12); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 20)); + x0 = _mm_add_epi32(x0, x1); + x3 = _mm_xor_si128(x3, x0); + x3 = _mm_shuffle_epi8(x3, x5); + x0 = _mm_shuffle_epi32(x0, 0x39); + x2 = _mm_add_epi32(x2, x3); + x3 = _mm_shuffle_epi32(x3, 0x4e); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_shuffle_epi32(x2, 0x93); + x6 = x1; + x1 = _mm_slli_epi32(x1, 7); + x1 = _mm_or_si128(x1, _mm_srli_epi32(x6, 25)); } x0 = _mm_add_epi32(x0, t0); diff --git a/scryptjane/scrypt-jane-mix_salsa-avx.h b/scryptjane/scrypt-jane-mix_salsa-avx.h index 15fb48e39..1ca90b5fa 100644 --- a/scryptjane/scrypt-jane-mix_salsa-avx.h +++ b/scryptjane/scrypt-jane-mix_salsa-avx.h @@ -120,7 +120,7 @@ asm_naked_fn(scrypt_ChunkMix_avx) a1(pop esi) a1(pop edi) a1(pop ebx) - a1(ret 16) + aret(16) asm_naked_fn_end(scrypt_ChunkMix_avx) #endif diff --git a/scryptjane/scrypt-jane-mix_salsa-sse2.h b/scryptjane/scrypt-jane-mix_salsa-sse2.h index 4898659e6..ecc5f0f8d 100644 --- a/scryptjane/scrypt-jane-mix_salsa-sse2.h +++ b/scryptjane/scrypt-jane-mix_salsa-sse2.h @@ -136,7 +136,7 @@ asm_naked_fn(scrypt_ChunkMix_sse2) a1(pop esi) a1(pop edi) a1(pop ebx) - a1(ret 16) + aret(16) asm_naked_fn_end(scrypt_ChunkMix_sse2) #endif @@ -426,7 +426,7 @@ scrypt_ChunkMix_sse2(uint32_t *Bout/*[chunkBytes]*/, uint32_t *Bin/*[chunkBytes] 4 9 14 3 */ - static void STDCALL + static void asm_calling_convention salsa_core_tangle_sse2(uint32_t *blocks, size_t count) { uint32_t t; while (count--) { diff --git a/scryptjane/scrypt-jane-mix_salsa64-avx.h b/scryptjane/scrypt-jane-mix_salsa64-avx.h new file mode 100644 index 000000000..50c9902d5 --- /dev/null +++ b/scryptjane/scrypt-jane-mix_salsa64-avx.h @@ -0,0 +1,367 @@ +/* x64 */ +#if defined(X86_64ASM_AVX) && (!defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED)) + +#define SCRYPT_SALSA64_AVX + +asm_naked_fn_proto(void, scrypt_ChunkMix_avx)(uint64_t *Bout/*[chunkBytes]*/, uint64_t *Bin/*[chunkBytes]*/, uint64_t *Bxor/*[chunkBytes]*/, uint32_t r) +asm_naked_fn(scrypt_ChunkMix_avx) + a1(push rbp) + a2(mov rbp, rsp) + a2(and rsp, ~63) + a2(sub rsp, 128) + a2(lea rcx,[rcx*2]) + a2(shl rcx,7) + a2(lea r9,[rcx-128]) + a2(lea rax,[rsi+r9]) + a2(lea r9,[rdx+r9]) + a2(and rdx, rdx) + a2(vmovdqa xmm0,[rax+0]) + a2(vmovdqa xmm1,[rax+16]) + a2(vmovdqa xmm2,[rax+32]) + a2(vmovdqa xmm3,[rax+48]) + a2(vmovdqa xmm4,[rax+64]) + a2(vmovdqa xmm5,[rax+80]) + a2(vmovdqa xmm6,[rax+96]) + a2(vmovdqa xmm7,[rax+112]) + a1(jz scrypt_ChunkMix_avx_no_xor1) + a3(vpxor xmm0,xmm0,[r9+0]) + a3(vpxor xmm1,xmm1,[r9+16]) + a3(vpxor xmm2,xmm2,[r9+32]) + a3(vpxor xmm3,xmm3,[r9+48]) + a3(vpxor xmm4,xmm4,[r9+64]) + a3(vpxor xmm5,xmm5,[r9+80]) + a3(vpxor xmm6,xmm6,[r9+96]) + a3(vpxor xmm7,xmm7,[r9+112]) + a1(scrypt_ChunkMix_avx_no_xor1:) + a2(xor r9,r9) + a2(xor r8,r8) + a1(scrypt_ChunkMix_avx_loop:) + a2(and rdx, rdx) + a3(vpxor xmm0,xmm0,[rsi+r9+0]) + a3(vpxor xmm1,xmm1,[rsi+r9+16]) + a3(vpxor xmm2,xmm2,[rsi+r9+32]) + a3(vpxor xmm3,xmm3,[rsi+r9+48]) + a3(vpxor xmm4,xmm4,[rsi+r9+64]) + a3(vpxor xmm5,xmm5,[rsi+r9+80]) + a3(vpxor xmm6,xmm6,[rsi+r9+96]) + a3(vpxor xmm7,xmm7,[rsi+r9+112]) + a1(jz scrypt_ChunkMix_avx_no_xor2) + a3(vpxor xmm0,xmm0,[rdx+r9+0]) + a3(vpxor xmm1,xmm1,[rdx+r9+16]) + a3(vpxor xmm2,xmm2,[rdx+r9+32]) + a3(vpxor xmm3,xmm3,[rdx+r9+48]) + a3(vpxor xmm4,xmm4,[rdx+r9+64]) + a3(vpxor xmm5,xmm5,[rdx+r9+80]) + a3(vpxor xmm6,xmm6,[rdx+r9+96]) + a3(vpxor xmm7,xmm7,[rdx+r9+112]) + a1(scrypt_ChunkMix_avx_no_xor2:) + a2(vmovdqa [rsp+0],xmm0) + a2(vmovdqa [rsp+16],xmm1) + a2(vmovdqa [rsp+32],xmm2) + a2(vmovdqa [rsp+48],xmm3) + a2(vmovdqa [rsp+64],xmm4) + a2(vmovdqa [rsp+80],xmm5) + a2(vmovdqa [rsp+96],xmm6) + a2(vmovdqa [rsp+112],xmm7) + a2(mov rax,8) + a1(scrypt_salsa64_avx_loop: ) + a3(vpaddq xmm8, xmm0, xmm2) + a3(vpaddq xmm9, xmm1, xmm3) + a3(vpshufd xmm8, xmm8, 0xb1) + a3(vpshufd xmm9, xmm9, 0xb1) + a3(vpxor xmm6, xmm6, xmm8) + a3(vpxor xmm7, xmm7, xmm9) + a3(vpaddq xmm10, xmm0, xmm6) + a3(vpaddq xmm11, xmm1, xmm7) + a3(vpsrlq xmm8, xmm10, 51) + a3(vpsrlq xmm9, xmm11, 51) + a3(vpsllq xmm10, xmm10, 13) + a3(vpsllq xmm11, xmm11, 13) + a3(vpxor xmm4, xmm4, xmm8) + a3(vpxor xmm5, xmm5, xmm9) + a3(vpxor xmm4, xmm4, xmm10) + a3(vpxor xmm5, xmm5, xmm11) + a3(vpaddq xmm8, xmm6, xmm4) + a3(vpaddq xmm9, xmm7, xmm5) + a3(vpsrlq xmm10, xmm8, 25) + a3(vpsrlq xmm11, xmm9, 25) + a3(vpsllq xmm8, xmm8, 39) + a3(vpsllq xmm9, xmm9, 39) + a3(vpxor xmm2, xmm2, xmm10) + a3(vpxor xmm3, xmm3, xmm11) + a3(vpxor xmm2, xmm2, xmm8) + a3(vpxor xmm3, xmm3, xmm9) + a3(vpaddq xmm10, xmm4, xmm2) + a3(vpaddq xmm11, xmm5, xmm3) + a3(vpshufd xmm10, xmm10, 0xb1) + a3(vpshufd xmm11, xmm11, 0xb1) + a3(vpxor xmm0, xmm0, xmm10) + a3(vpxor xmm1, xmm1, xmm11) + a2(vmovdqa xmm8, xmm2) + a2(vmovdqa xmm9, xmm3) + a4(vpalignr xmm2, xmm6, xmm7, 8) + a4(vpalignr xmm3, xmm7, xmm6, 8) + a4(vpalignr xmm6, xmm9, xmm8, 8) + a4(vpalignr xmm7, xmm8, xmm9, 8) + a2(sub rax, 2) + a3(vpaddq xmm10, xmm0, xmm2) + a3(vpaddq xmm11, xmm1, xmm3) + a3(vpshufd xmm10, xmm10, 0xb1) + a3(vpshufd xmm11, xmm11, 0xb1) + a3(vpxor xmm6, xmm6, xmm10) + a3(vpxor xmm7, xmm7, xmm11) + a3(vpaddq xmm8, xmm0, xmm6) + a3(vpaddq xmm9, xmm1, xmm7) + a3(vpsrlq xmm10, xmm8, 51) + a3(vpsrlq xmm11, xmm9, 51) + a3(vpsllq xmm8, xmm8, 13) + a3(vpsllq xmm9, xmm9, 13) + a3(vpxor xmm5, xmm5, xmm10) + a3(vpxor xmm4, xmm4, xmm11) + a3(vpxor xmm5, xmm5, xmm8) + a3(vpxor xmm4, xmm4, xmm9) + a3(vpaddq xmm10, xmm6, xmm5) + a3(vpaddq xmm11, xmm7, xmm4) + a3(vpsrlq xmm8, xmm10, 25) + a3(vpsrlq xmm9, xmm11, 25) + a3(vpsllq xmm10, xmm10, 39) + a3(vpsllq xmm11, xmm11, 39) + a3(vpxor xmm2, xmm2, xmm8) + a3(vpxor xmm3, xmm3, xmm9) + a3(vpxor xmm2, xmm2, xmm10) + a3(vpxor xmm3, xmm3, xmm11) + a3(vpaddq xmm8, xmm5, xmm2) + a3(vpaddq xmm9, xmm4, xmm3) + a3(vpshufd xmm8, xmm8, 0xb1) + a3(vpshufd xmm9, xmm9, 0xb1) + a3(vpxor xmm0, xmm0, xmm8) + a3(vpxor xmm1, xmm1, xmm9) + a2(vmovdqa xmm10, xmm2) + a2(vmovdqa xmm11, xmm3) + a4(vpalignr xmm2, xmm6, xmm7, 8) + a4(vpalignr xmm3, xmm7, xmm6, 8) + a4(vpalignr xmm6, xmm11, xmm10, 8) + a4(vpalignr xmm7, xmm10, xmm11, 8) + a1(ja scrypt_salsa64_avx_loop) + a3(vpaddq xmm0,xmm0,[rsp+0]) + a3(vpaddq xmm1,xmm1,[rsp+16]) + a3(vpaddq xmm2,xmm2,[rsp+32]) + a3(vpaddq xmm3,xmm3,[rsp+48]) + a3(vpaddq xmm4,xmm4,[rsp+64]) + a3(vpaddq xmm5,xmm5,[rsp+80]) + a3(vpaddq xmm6,xmm6,[rsp+96]) + a3(vpaddq xmm7,xmm7,[rsp+112]) + a2(lea rax,[r8+r9]) + a2(xor r8,rcx) + a2(and rax,~0xff) + a2(add r9,128) + a2(shr rax,1) + a2(add rax, rdi) + a2(cmp r9,rcx) + a2(vmovdqa [rax+0],xmm0) + a2(vmovdqa [rax+16],xmm1) + a2(vmovdqa [rax+32],xmm2) + a2(vmovdqa [rax+48],xmm3) + a2(vmovdqa [rax+64],xmm4) + a2(vmovdqa [rax+80],xmm5) + a2(vmovdqa [rax+96],xmm6) + a2(vmovdqa [rax+112],xmm7) + a1(jne scrypt_ChunkMix_avx_loop) + a2(mov rsp, rbp) + a1(pop rbp) + a1(ret) +asm_naked_fn_end(scrypt_ChunkMix_avx) + +#endif + + +/* intrinsic */ +#if defined(X86_INTRINSIC_AVX) && (!defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED)) && !defined(SCRYPT_SALSA64_AVX) + +#define SCRYPT_SALSA64_AVX + +static void asm_calling_convention +scrypt_ChunkMix_avx(uint64_t *Bout/*[chunkBytes]*/, uint64_t *Bin/*[chunkBytes]*/, uint64_t *Bxor/*[chunkBytes]*/, uint32_t r) { + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x4,x5,x6,x7,t0,t1,t2,t3,t4,t5,t6,t7,z0,z1,z2,z3; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + x4 = xmmp[4]; + x5 = xmmp[5]; + x6 = xmmp[6]; + x7 = xmmp[7]; + + if (Bxor) { + xmmp = (xmmi *)scrypt_block(Bxor, blocksPerChunk - 1); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + } + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + + if (Bxor) { + xmmp = (xmmi *)scrypt_block(Bxor, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + } + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + t4 = x4; + t5 = x5; + t6 = x6; + t7 = x7; + + for (rounds = 8; rounds; rounds -= 2) { + z0 = _mm_add_epi64(x0, x2); + z1 = _mm_add_epi64(x1, x3); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x6 = _mm_xor_si128(x6, z0); + x7 = _mm_xor_si128(x7, z1); + + z0 = _mm_add_epi64(x6, x0); + z1 = _mm_add_epi64(x7, x1); + z2 = _mm_srli_epi64(z0, 64-13); + z3 = _mm_srli_epi64(z1, 64-13); + z0 = _mm_slli_epi64(z0, 13); + z1 = _mm_slli_epi64(z1, 13); + x4 = _mm_xor_si128(x4, z2); + x5 = _mm_xor_si128(x5, z3); + x4 = _mm_xor_si128(x4, z0); + x5 = _mm_xor_si128(x5, z1); + + z0 = _mm_add_epi64(x4, x6); + z1 = _mm_add_epi64(x5, x7); + z2 = _mm_srli_epi64(z0, 64-39); + z3 = _mm_srli_epi64(z1, 64-39); + z0 = _mm_slli_epi64(z0, 39); + z1 = _mm_slli_epi64(z1, 39); + x2 = _mm_xor_si128(x2, z2); + x3 = _mm_xor_si128(x3, z3); + x2 = _mm_xor_si128(x2, z0); + x3 = _mm_xor_si128(x3, z1); + + z0 = _mm_add_epi64(x2, x4); + z1 = _mm_add_epi64(x3, x5); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x0 = _mm_xor_si128(x0, z0); + x1 = _mm_xor_si128(x1, z1); + + z0 = x2; + z1 = x3; + x2 = _mm_alignr_epi8(x6, x7, 8); + x3 = _mm_alignr_epi8(x7, x6, 8); + x6 = _mm_alignr_epi8(z1, z0, 8); + x7 = _mm_alignr_epi8(z0, z1, 8); + + z0 = _mm_add_epi64(x0, x2); + z1 = _mm_add_epi64(x1, x3); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x6 = _mm_xor_si128(x6, z0); + x7 = _mm_xor_si128(x7, z1); + + z0 = _mm_add_epi64(x6, x0); + z1 = _mm_add_epi64(x7, x1); + z2 = _mm_srli_epi64(z0, 64-13); + z3 = _mm_srli_epi64(z1, 64-13); + z0 = _mm_slli_epi64(z0, 13); + z1 = _mm_slli_epi64(z1, 13); + x5 = _mm_xor_si128(x5, z2); + x4 = _mm_xor_si128(x4, z3); + x5 = _mm_xor_si128(x5, z0); + x4 = _mm_xor_si128(x4, z1); + + z0 = _mm_add_epi64(x5, x6); + z1 = _mm_add_epi64(x4, x7); + z2 = _mm_srli_epi64(z0, 64-39); + z3 = _mm_srli_epi64(z1, 64-39); + z0 = _mm_slli_epi64(z0, 39); + z1 = _mm_slli_epi64(z1, 39); + x2 = _mm_xor_si128(x2, z2); + x3 = _mm_xor_si128(x3, z3); + x2 = _mm_xor_si128(x2, z0); + x3 = _mm_xor_si128(x3, z1); + + z0 = _mm_add_epi64(x2, x5); + z1 = _mm_add_epi64(x3, x4); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x0 = _mm_xor_si128(x0, z0); + x1 = _mm_xor_si128(x1, z1); + + z0 = x2; + z1 = x3; + x2 = _mm_alignr_epi8(x6, x7, 8); + x3 = _mm_alignr_epi8(x7, x6, 8); + x6 = _mm_alignr_epi8(z1, z0, 8); + x7 = _mm_alignr_epi8(z0, z1, 8); + } + + x0 = _mm_add_epi64(x0, t0); + x1 = _mm_add_epi64(x1, t1); + x2 = _mm_add_epi64(x2, t2); + x3 = _mm_add_epi64(x3, t3); + x4 = _mm_add_epi64(x4, t4); + x5 = _mm_add_epi64(x5, t5); + x6 = _mm_add_epi64(x6, t6); + x7 = _mm_add_epi64(x7, t7); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + xmmp[4] = x4; + xmmp[5] = x5; + xmmp[6] = x6; + xmmp[7] = x7; + } +} + +#endif + +#if defined(SCRYPT_SALSA64_AVX) + /* uses salsa64_core_tangle_sse2 */ + + #undef SCRYPT_MIX + #define SCRYPT_MIX "Salsa64/8-AVX" + #undef SCRYPT_SALSA64_INCLUDED + #define SCRYPT_SALSA64_INCLUDED +#endif diff --git a/scryptjane/scrypt-jane-mix_salsa64-sse2.h b/scryptjane/scrypt-jane-mix_salsa64-sse2.h new file mode 100644 index 000000000..f8d957432 --- /dev/null +++ b/scryptjane/scrypt-jane-mix_salsa64-sse2.h @@ -0,0 +1,449 @@ +/* x64 */ +#if defined(X86_64ASM_SSE2) && (!defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED)) + +#define SCRYPT_SALSA64_SSE2 + +asm_naked_fn_proto(void, scrypt_ChunkMix_sse2)(uint64_t *Bout/*[chunkBytes]*/, uint64_t *Bin/*[chunkBytes]*/, uint64_t *Bxor/*[chunkBytes]*/, uint32_t r) +asm_naked_fn(scrypt_ChunkMix_sse2) + a1(push rbp) + a2(mov rbp, rsp) + a2(and rsp, ~63) + a2(sub rsp, 128) + a2(lea rcx,[rcx*2]) + a2(shl rcx,7) + a2(lea r9,[rcx-128]) + a2(lea rax,[rsi+r9]) + a2(lea r9,[rdx+r9]) + a2(and rdx, rdx) + a2(movdqa xmm0,[rax+0]) + a2(movdqa xmm1,[rax+16]) + a2(movdqa xmm2,[rax+32]) + a2(movdqa xmm3,[rax+48]) + a2(movdqa xmm4,[rax+64]) + a2(movdqa xmm5,[rax+80]) + a2(movdqa xmm6,[rax+96]) + a2(movdqa xmm7,[rax+112]) + a1(jz scrypt_ChunkMix_sse2_no_xor1) + a2(pxor xmm0,[r9+0]) + a2(pxor xmm1,[r9+16]) + a2(pxor xmm2,[r9+32]) + a2(pxor xmm3,[r9+48]) + a2(pxor xmm4,[r9+64]) + a2(pxor xmm5,[r9+80]) + a2(pxor xmm6,[r9+96]) + a2(pxor xmm7,[r9+112]) + a1(scrypt_ChunkMix_sse2_no_xor1:) + a2(xor r9,r9) + a2(xor r8,r8) + a1(scrypt_ChunkMix_sse2_loop:) + a2(and rdx, rdx) + a2(pxor xmm0,[rsi+r9+0]) + a2(pxor xmm1,[rsi+r9+16]) + a2(pxor xmm2,[rsi+r9+32]) + a2(pxor xmm3,[rsi+r9+48]) + a2(pxor xmm4,[rsi+r9+64]) + a2(pxor xmm5,[rsi+r9+80]) + a2(pxor xmm6,[rsi+r9+96]) + a2(pxor xmm7,[rsi+r9+112]) + a1(jz scrypt_ChunkMix_sse2_no_xor2) + a2(pxor xmm0,[rdx+r9+0]) + a2(pxor xmm1,[rdx+r9+16]) + a2(pxor xmm2,[rdx+r9+32]) + a2(pxor xmm3,[rdx+r9+48]) + a2(pxor xmm4,[rdx+r9+64]) + a2(pxor xmm5,[rdx+r9+80]) + a2(pxor xmm6,[rdx+r9+96]) + a2(pxor xmm7,[rdx+r9+112]) + a1(scrypt_ChunkMix_sse2_no_xor2:) + a2(movdqa [rsp+0],xmm0) + a2(movdqa [rsp+16],xmm1) + a2(movdqa [rsp+32],xmm2) + a2(movdqa [rsp+48],xmm3) + a2(movdqa [rsp+64],xmm4) + a2(movdqa [rsp+80],xmm5) + a2(movdqa [rsp+96],xmm6) + a2(movdqa [rsp+112],xmm7) + a2(mov rax,8) + a1(scrypt_salsa64_sse2_loop: ) + a2(movdqa xmm8, xmm0) + a2(movdqa xmm9, xmm1) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm6, xmm8) + a2(pxor xmm7, xmm9) + a2(movdqa xmm10, xmm0) + a2(movdqa xmm11, xmm1) + a2(paddq xmm10, xmm6) + a2(paddq xmm11, xmm7) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 51) + a2(psrlq xmm11, 51) + a2(psllq xmm8, 13) + a2(psllq xmm9, 13) + a2(pxor xmm4, xmm10) + a2(pxor xmm5, xmm11) + a2(pxor xmm4, xmm8) + a2(pxor xmm5, xmm9) + a2(movdqa xmm10, xmm6) + a2(movdqa xmm11, xmm7) + a2(paddq xmm10, xmm4) + a2(paddq xmm11, xmm5) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 25) + a2(psrlq xmm11, 25) + a2(psllq xmm8, 39) + a2(psllq xmm9, 39) + a2(pxor xmm2, xmm10) + a2(pxor xmm3, xmm11) + a2(pxor xmm2, xmm8) + a2(pxor xmm3, xmm9) + a2(movdqa xmm8, xmm4) + a2(movdqa xmm9, xmm5) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm0, xmm8) + a2(pxor xmm1, xmm9) + a2(movdqa xmm8, xmm2) + a2(movdqa xmm9, xmm3) + a2(movdqa xmm10, xmm6) + a2(movdqa xmm11, xmm7) + a2(movdqa xmm2, xmm7) + a2(movdqa xmm3, xmm6) + a2(punpcklqdq xmm10, xmm6) + a2(punpcklqdq xmm11, xmm7) + a2(movdqa xmm6, xmm8) + a2(movdqa xmm7, xmm9) + a2(punpcklqdq xmm9, xmm9) + a2(punpcklqdq xmm8, xmm8) + a2(punpckhqdq xmm2, xmm10) + a2(punpckhqdq xmm3, xmm11) + a2(punpckhqdq xmm6, xmm9) + a2(punpckhqdq xmm7, xmm8) + a2(sub rax, 2) + a2(movdqa xmm8, xmm0) + a2(movdqa xmm9, xmm1) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm6, xmm8) + a2(pxor xmm7, xmm9) + a2(movdqa xmm10, xmm0) + a2(movdqa xmm11, xmm1) + a2(paddq xmm10, xmm6) + a2(paddq xmm11, xmm7) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 51) + a2(psrlq xmm11, 51) + a2(psllq xmm8, 13) + a2(psllq xmm9, 13) + a2(pxor xmm5, xmm10) + a2(pxor xmm4, xmm11) + a2(pxor xmm5, xmm8) + a2(pxor xmm4, xmm9) + a2(movdqa xmm10, xmm6) + a2(movdqa xmm11, xmm7) + a2(paddq xmm10, xmm5) + a2(paddq xmm11, xmm4) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 25) + a2(psrlq xmm11, 25) + a2(psllq xmm8, 39) + a2(psllq xmm9, 39) + a2(pxor xmm2, xmm10) + a2(pxor xmm3, xmm11) + a2(pxor xmm2, xmm8) + a2(pxor xmm3, xmm9) + a2(movdqa xmm8, xmm5) + a2(movdqa xmm9, xmm4) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm0, xmm8) + a2(pxor xmm1, xmm9) + a2(movdqa xmm8, xmm2) + a2(movdqa xmm9, xmm3) + a2(movdqa xmm10, xmm6) + a2(movdqa xmm11, xmm7) + a2(movdqa xmm2, xmm7) + a2(movdqa xmm3, xmm6) + a2(punpcklqdq xmm10, xmm6) + a2(punpcklqdq xmm11, xmm7) + a2(movdqa xmm6, xmm8) + a2(movdqa xmm7, xmm9) + a2(punpcklqdq xmm9, xmm9) + a2(punpcklqdq xmm8, xmm8) + a2(punpckhqdq xmm2, xmm10) + a2(punpckhqdq xmm3, xmm11) + a2(punpckhqdq xmm6, xmm9) + a2(punpckhqdq xmm7, xmm8) + a1(ja scrypt_salsa64_sse2_loop) + a2(paddq xmm0,[rsp+0]) + a2(paddq xmm1,[rsp+16]) + a2(paddq xmm2,[rsp+32]) + a2(paddq xmm3,[rsp+48]) + a2(paddq xmm4,[rsp+64]) + a2(paddq xmm5,[rsp+80]) + a2(paddq xmm6,[rsp+96]) + a2(paddq xmm7,[rsp+112]) + a2(lea rax,[r8+r9]) + a2(xor r8,rcx) + a2(and rax,~0xff) + a2(add r9,128) + a2(shr rax,1) + a2(add rax, rdi) + a2(cmp r9,rcx) + a2(movdqa [rax+0],xmm0) + a2(movdqa [rax+16],xmm1) + a2(movdqa [rax+32],xmm2) + a2(movdqa [rax+48],xmm3) + a2(movdqa [rax+64],xmm4) + a2(movdqa [rax+80],xmm5) + a2(movdqa [rax+96],xmm6) + a2(movdqa [rax+112],xmm7) + a1(jne scrypt_ChunkMix_sse2_loop) + a2(mov rsp, rbp) + a1(pop rbp) + a1(ret) +asm_naked_fn_end(scrypt_ChunkMix_sse2) + +#endif + + +/* intrinsic */ +#if defined(X86_INTRINSIC_SSE2) && (!defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED)) && !defined(SCRYPT_SALSA64_SSE2) + +#define SCRYPT_SALSA64_SSE2 + +static void asm_calling_convention +scrypt_ChunkMix_sse2(uint64_t *Bout/*[chunkBytes]*/, uint64_t *Bin/*[chunkBytes]*/, uint64_t *Bxor/*[chunkBytes]*/, uint32_t r) { + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x4,x5,x6,x7,t0,t1,t2,t3,t4,t5,t6,t7,z0,z1,z2,z3; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + x4 = xmmp[4]; + x5 = xmmp[5]; + x6 = xmmp[6]; + x7 = xmmp[7]; + + if (Bxor) { + xmmp = (xmmi *)scrypt_block(Bxor, blocksPerChunk - 1); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + } + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + + if (Bxor) { + xmmp = (xmmi *)scrypt_block(Bxor, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + } + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + t4 = x4; + t5 = x5; + t6 = x6; + t7 = x7; + + for (rounds = 8; rounds; rounds -= 2) { + z0 = _mm_add_epi64(x0, x2); + z1 = _mm_add_epi64(x1, x3); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x6 = _mm_xor_si128(x6, z0); + x7 = _mm_xor_si128(x7, z1); + + z0 = _mm_add_epi64(x6, x0); + z1 = _mm_add_epi64(x7, x1); + z2 = _mm_srli_epi64(z0, 64-13); + z3 = _mm_srli_epi64(z1, 64-13); + z0 = _mm_slli_epi64(z0, 13); + z1 = _mm_slli_epi64(z1, 13); + x4 = _mm_xor_si128(x4, z2); + x5 = _mm_xor_si128(x5, z3); + x4 = _mm_xor_si128(x4, z0); + x5 = _mm_xor_si128(x5, z1); + + z0 = _mm_add_epi64(x4, x6); + z1 = _mm_add_epi64(x5, x7); + z2 = _mm_srli_epi64(z0, 64-39); + z3 = _mm_srli_epi64(z1, 64-39); + z0 = _mm_slli_epi64(z0, 39); + z1 = _mm_slli_epi64(z1, 39); + x2 = _mm_xor_si128(x2, z2); + x3 = _mm_xor_si128(x3, z3); + x2 = _mm_xor_si128(x2, z0); + x3 = _mm_xor_si128(x3, z1); + + z0 = _mm_add_epi64(x2, x4); + z1 = _mm_add_epi64(x3, x5); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x0 = _mm_xor_si128(x0, z0); + x1 = _mm_xor_si128(x1, z1); + + z0 = x4; + z1 = x5; + z2 = x2; + z3 = x3; + x4 = z1; + x5 = z0; + x2 = _mm_unpackhi_epi64(x7, _mm_unpacklo_epi64(x6, x6)); + x3 = _mm_unpackhi_epi64(x6, _mm_unpacklo_epi64(x7, x7)); + x6 = _mm_unpackhi_epi64(z2, _mm_unpacklo_epi64(z3, z3)); + x7 = _mm_unpackhi_epi64(z3, _mm_unpacklo_epi64(z2, z2)); + + z0 = _mm_add_epi64(x0, x2); + z1 = _mm_add_epi64(x1, x3); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x6 = _mm_xor_si128(x6, z0); + x7 = _mm_xor_si128(x7, z1); + + z0 = _mm_add_epi64(x6, x0); + z1 = _mm_add_epi64(x7, x1); + z2 = _mm_srli_epi64(z0, 64-13); + z3 = _mm_srli_epi64(z1, 64-13); + z0 = _mm_slli_epi64(z0, 13); + z1 = _mm_slli_epi64(z1, 13); + x4 = _mm_xor_si128(x4, z2); + x5 = _mm_xor_si128(x5, z3); + x4 = _mm_xor_si128(x4, z0); + x5 = _mm_xor_si128(x5, z1); + + z0 = _mm_add_epi64(x4, x6); + z1 = _mm_add_epi64(x5, x7); + z2 = _mm_srli_epi64(z0, 64-39); + z3 = _mm_srli_epi64(z1, 64-39); + z0 = _mm_slli_epi64(z0, 39); + z1 = _mm_slli_epi64(z1, 39); + x2 = _mm_xor_si128(x2, z2); + x3 = _mm_xor_si128(x3, z3); + x2 = _mm_xor_si128(x2, z0); + x3 = _mm_xor_si128(x3, z1); + + z0 = _mm_add_epi64(x2, x4); + z1 = _mm_add_epi64(x3, x5); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x0 = _mm_xor_si128(x0, z0); + x1 = _mm_xor_si128(x1, z1); + + z0 = x4; + z1 = x5; + z2 = x2; + z3 = x3; + x4 = z1; + x5 = z0; + x2 = _mm_unpackhi_epi64(x7, _mm_unpacklo_epi64(x6, x6)); + x3 = _mm_unpackhi_epi64(x6, _mm_unpacklo_epi64(x7, x7)); + x6 = _mm_unpackhi_epi64(z2, _mm_unpacklo_epi64(z3, z3)); + x7 = _mm_unpackhi_epi64(z3, _mm_unpacklo_epi64(z2, z2)); + } + + x0 = _mm_add_epi64(x0, t0); + x1 = _mm_add_epi64(x1, t1); + x2 = _mm_add_epi64(x2, t2); + x3 = _mm_add_epi64(x3, t3); + x4 = _mm_add_epi64(x4, t4); + x5 = _mm_add_epi64(x5, t5); + x6 = _mm_add_epi64(x6, t6); + x7 = _mm_add_epi64(x7, t7); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + xmmp[4] = x4; + xmmp[5] = x5; + xmmp[6] = x6; + xmmp[7] = x7; + } +} + +#endif + +#if defined(SCRYPT_SALSA64_SSE2) + #undef SCRYPT_MIX + #define SCRYPT_MIX "Salsa64/8-SSE2" + #undef SCRYPT_SALSA64_INCLUDED + #define SCRYPT_SALSA64_INCLUDED +#endif + +/* sse3/avx use this as well */ +#if defined(SCRYPT_SALSA64_INCLUDED) + /* + Default layout: + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 + + SSE2 layout: + 0 5 10 15 + 12 1 6 11 + 8 13 2 7 + 4 9 14 3 + */ + + + static void asm_calling_convention + salsa64_core_tangle_sse2(uint64_t *blocks, size_t count) { + uint64_t t; + while (count--) { + t = blocks[1]; blocks[1] = blocks[5]; blocks[5] = t; + t = blocks[2]; blocks[2] = blocks[10]; blocks[10] = t; + t = blocks[3]; blocks[3] = blocks[15]; blocks[15] = t; + t = blocks[4]; blocks[4] = blocks[12]; blocks[12] = t; + t = blocks[7]; blocks[7] = blocks[11]; blocks[11] = t; + t = blocks[9]; blocks[9] = blocks[13]; blocks[13] = t; + blocks += 16; + } + } +#endif \ No newline at end of file diff --git a/scryptjane/scrypt-jane-mix_salsa64-ssse3.h b/scryptjane/scrypt-jane-mix_salsa64-ssse3.h new file mode 100644 index 000000000..bebfe5cb5 --- /dev/null +++ b/scryptjane/scrypt-jane-mix_salsa64-ssse3.h @@ -0,0 +1,399 @@ +/* x64 */ +#if defined(X86_64ASM_SSSE3) && (!defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED)) + +#define SCRYPT_SALSA64_SSSE3 + +asm_naked_fn_proto(void, scrypt_ChunkMix_ssse3)(uint64_t *Bout/*[chunkBytes]*/, uint64_t *Bin/*[chunkBytes]*/, uint64_t *Bxor/*[chunkBytes]*/, uint32_t r) +asm_naked_fn(scrypt_ChunkMix_ssse3) + a1(push rbp) + a2(mov rbp, rsp) + a2(and rsp, ~63) + a2(sub rsp, 128) + a2(lea rcx,[rcx*2]) + a2(shl rcx,7) + a2(lea r9,[rcx-128]) + a2(lea rax,[rsi+r9]) + a2(lea r9,[rdx+r9]) + a2(and rdx, rdx) + a2(movdqa xmm0,[rax+0]) + a2(movdqa xmm1,[rax+16]) + a2(movdqa xmm2,[rax+32]) + a2(movdqa xmm3,[rax+48]) + a2(movdqa xmm4,[rax+64]) + a2(movdqa xmm5,[rax+80]) + a2(movdqa xmm6,[rax+96]) + a2(movdqa xmm7,[rax+112]) + a1(jz scrypt_ChunkMix_ssse3_no_xor1) + a2(pxor xmm0,[r9+0]) + a2(pxor xmm1,[r9+16]) + a2(pxor xmm2,[r9+32]) + a2(pxor xmm3,[r9+48]) + a2(pxor xmm4,[r9+64]) + a2(pxor xmm5,[r9+80]) + a2(pxor xmm6,[r9+96]) + a2(pxor xmm7,[r9+112]) + a1(scrypt_ChunkMix_ssse3_no_xor1:) + a2(xor r9,r9) + a2(xor r8,r8) + a1(scrypt_ChunkMix_ssse3_loop:) + a2(and rdx, rdx) + a2(pxor xmm0,[rsi+r9+0]) + a2(pxor xmm1,[rsi+r9+16]) + a2(pxor xmm2,[rsi+r9+32]) + a2(pxor xmm3,[rsi+r9+48]) + a2(pxor xmm4,[rsi+r9+64]) + a2(pxor xmm5,[rsi+r9+80]) + a2(pxor xmm6,[rsi+r9+96]) + a2(pxor xmm7,[rsi+r9+112]) + a1(jz scrypt_ChunkMix_ssse3_no_xor2) + a2(pxor xmm0,[rdx+r9+0]) + a2(pxor xmm1,[rdx+r9+16]) + a2(pxor xmm2,[rdx+r9+32]) + a2(pxor xmm3,[rdx+r9+48]) + a2(pxor xmm4,[rdx+r9+64]) + a2(pxor xmm5,[rdx+r9+80]) + a2(pxor xmm6,[rdx+r9+96]) + a2(pxor xmm7,[rdx+r9+112]) + a1(scrypt_ChunkMix_ssse3_no_xor2:) + a2(movdqa [rsp+0],xmm0) + a2(movdqa [rsp+16],xmm1) + a2(movdqa [rsp+32],xmm2) + a2(movdqa [rsp+48],xmm3) + a2(movdqa [rsp+64],xmm4) + a2(movdqa [rsp+80],xmm5) + a2(movdqa [rsp+96],xmm6) + a2(movdqa [rsp+112],xmm7) + a2(mov rax,8) + a1(scrypt_salsa64_ssse3_loop: ) + a2(movdqa xmm8, xmm0) + a2(movdqa xmm9, xmm1) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm6, xmm8) + a2(pxor xmm7, xmm9) + a2(movdqa xmm10, xmm0) + a2(movdqa xmm11, xmm1) + a2(paddq xmm10, xmm6) + a2(paddq xmm11, xmm7) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 51) + a2(psrlq xmm11, 51) + a2(psllq xmm8, 13) + a2(psllq xmm9, 13) + a2(pxor xmm4, xmm10) + a2(pxor xmm5, xmm11) + a2(pxor xmm4, xmm8) + a2(pxor xmm5, xmm9) + a2(movdqa xmm10, xmm6) + a2(movdqa xmm11, xmm7) + a2(paddq xmm10, xmm4) + a2(paddq xmm11, xmm5) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 25) + a2(psrlq xmm11, 25) + a2(psllq xmm8, 39) + a2(psllq xmm9, 39) + a2(pxor xmm2, xmm10) + a2(pxor xmm3, xmm11) + a2(pxor xmm2, xmm8) + a2(pxor xmm3, xmm9) + a2(movdqa xmm8, xmm4) + a2(movdqa xmm9, xmm5) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm0, xmm8) + a2(pxor xmm1, xmm9) + a2(movdqa xmm10, xmm2) + a2(movdqa xmm11, xmm3) + a2(movdqa xmm2, xmm6) + a2(movdqa xmm3, xmm7) + a3(palignr xmm2, xmm7, 8) + a3(palignr xmm3, xmm6, 8) + a2(movdqa xmm6, xmm11) + a2(movdqa xmm7, xmm10) + a3(palignr xmm6, xmm10, 8) + a3(palignr xmm7, xmm11, 8) + a2(sub rax, 2) + a2(movdqa xmm8, xmm0) + a2(movdqa xmm9, xmm1) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm6, xmm8) + a2(pxor xmm7, xmm9) + a2(movdqa xmm10, xmm0) + a2(movdqa xmm11, xmm1) + a2(paddq xmm10, xmm6) + a2(paddq xmm11, xmm7) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 51) + a2(psrlq xmm11, 51) + a2(psllq xmm8, 13) + a2(psllq xmm9, 13) + a2(pxor xmm5, xmm10) + a2(pxor xmm4, xmm11) + a2(pxor xmm5, xmm8) + a2(pxor xmm4, xmm9) + a2(movdqa xmm10, xmm6) + a2(movdqa xmm11, xmm7) + a2(paddq xmm10, xmm5) + a2(paddq xmm11, xmm4) + a2(movdqa xmm8, xmm10) + a2(movdqa xmm9, xmm11) + a2(psrlq xmm10, 25) + a2(psrlq xmm11, 25) + a2(psllq xmm8, 39) + a2(psllq xmm9, 39) + a2(pxor xmm2, xmm10) + a2(pxor xmm3, xmm11) + a2(pxor xmm2, xmm8) + a2(pxor xmm3, xmm9) + a2(movdqa xmm8, xmm5) + a2(movdqa xmm9, xmm4) + a2(paddq xmm8, xmm2) + a2(paddq xmm9, xmm3) + a3(pshufd xmm8, xmm8, 0xb1) + a3(pshufd xmm9, xmm9, 0xb1) + a2(pxor xmm0, xmm8) + a2(pxor xmm1, xmm9) + a2(movdqa xmm10, xmm2) + a2(movdqa xmm11, xmm3) + a2(movdqa xmm2, xmm6) + a2(movdqa xmm3, xmm7) + a3(palignr xmm2, xmm7, 8) + a3(palignr xmm3, xmm6, 8) + a2(movdqa xmm6, xmm11) + a2(movdqa xmm7, xmm10) + a3(palignr xmm6, xmm10, 8) + a3(palignr xmm7, xmm11, 8) + a1(ja scrypt_salsa64_ssse3_loop) + a2(paddq xmm0,[rsp+0]) + a2(paddq xmm1,[rsp+16]) + a2(paddq xmm2,[rsp+32]) + a2(paddq xmm3,[rsp+48]) + a2(paddq xmm4,[rsp+64]) + a2(paddq xmm5,[rsp+80]) + a2(paddq xmm6,[rsp+96]) + a2(paddq xmm7,[rsp+112]) + a2(lea rax,[r8+r9]) + a2(xor r8,rcx) + a2(and rax,~0xff) + a2(add r9,128) + a2(shr rax,1) + a2(add rax, rdi) + a2(cmp r9,rcx) + a2(movdqa [rax+0],xmm0) + a2(movdqa [rax+16],xmm1) + a2(movdqa [rax+32],xmm2) + a2(movdqa [rax+48],xmm3) + a2(movdqa [rax+64],xmm4) + a2(movdqa [rax+80],xmm5) + a2(movdqa [rax+96],xmm6) + a2(movdqa [rax+112],xmm7) + a1(jne scrypt_ChunkMix_ssse3_loop) + a2(mov rsp, rbp) + a1(pop rbp) + a1(ret) +asm_naked_fn_end(scrypt_ChunkMix_ssse3) + +#endif + + +/* intrinsic */ +#if defined(X86_INTRINSIC_SSSE3) && (!defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED)) && !defined(SCRYPT_SALSA64_SSSE3) + +#define SCRYPT_SALSA64_SSSE3 + +static void asm_calling_convention +scrypt_ChunkMix_ssse3(uint64_t *Bout/*[chunkBytes]*/, uint64_t *Bin/*[chunkBytes]*/, uint64_t *Bxor/*[chunkBytes]*/, uint32_t r) { + uint32_t i, blocksPerChunk = r * 2, half = 0; + xmmi *xmmp,x0,x1,x2,x3,x4,x5,x6,x7,t0,t1,t2,t3,t4,t5,t6,t7,z0,z1,z2,z3; + size_t rounds; + + /* 1: X = B_{2r - 1} */ + xmmp = (xmmi *)scrypt_block(Bin, blocksPerChunk - 1); + x0 = xmmp[0]; + x1 = xmmp[1]; + x2 = xmmp[2]; + x3 = xmmp[3]; + x4 = xmmp[4]; + x5 = xmmp[5]; + x6 = xmmp[6]; + x7 = xmmp[7]; + + if (Bxor) { + xmmp = (xmmi *)scrypt_block(Bxor, blocksPerChunk - 1); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + } + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < blocksPerChunk; i++, half ^= r) { + /* 3: X = H(X ^ B_i) */ + xmmp = (xmmi *)scrypt_block(Bin, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + + if (Bxor) { + xmmp = (xmmi *)scrypt_block(Bxor, i); + x0 = _mm_xor_si128(x0, xmmp[0]); + x1 = _mm_xor_si128(x1, xmmp[1]); + x2 = _mm_xor_si128(x2, xmmp[2]); + x3 = _mm_xor_si128(x3, xmmp[3]); + x4 = _mm_xor_si128(x4, xmmp[4]); + x5 = _mm_xor_si128(x5, xmmp[5]); + x6 = _mm_xor_si128(x6, xmmp[6]); + x7 = _mm_xor_si128(x7, xmmp[7]); + } + + t0 = x0; + t1 = x1; + t2 = x2; + t3 = x3; + t4 = x4; + t5 = x5; + t6 = x6; + t7 = x7; + + for (rounds = 8; rounds; rounds -= 2) { + z0 = _mm_add_epi64(x0, x2); + z1 = _mm_add_epi64(x1, x3); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x6 = _mm_xor_si128(x6, z0); + x7 = _mm_xor_si128(x7, z1); + + z0 = _mm_add_epi64(x6, x0); + z1 = _mm_add_epi64(x7, x1); + z2 = _mm_srli_epi64(z0, 64-13); + z3 = _mm_srli_epi64(z1, 64-13); + z0 = _mm_slli_epi64(z0, 13); + z1 = _mm_slli_epi64(z1, 13); + x4 = _mm_xor_si128(x4, z2); + x5 = _mm_xor_si128(x5, z3); + x4 = _mm_xor_si128(x4, z0); + x5 = _mm_xor_si128(x5, z1); + + z0 = _mm_add_epi64(x4, x6); + z1 = _mm_add_epi64(x5, x7); + z2 = _mm_srli_epi64(z0, 64-39); + z3 = _mm_srli_epi64(z1, 64-39); + z0 = _mm_slli_epi64(z0, 39); + z1 = _mm_slli_epi64(z1, 39); + x2 = _mm_xor_si128(x2, z2); + x3 = _mm_xor_si128(x3, z3); + x2 = _mm_xor_si128(x2, z0); + x3 = _mm_xor_si128(x3, z1); + + z0 = _mm_add_epi64(x2, x4); + z1 = _mm_add_epi64(x3, x5); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x0 = _mm_xor_si128(x0, z0); + x1 = _mm_xor_si128(x1, z1); + + z0 = x2; + z1 = x3; + x2 = _mm_alignr_epi8(x6, x7, 8); + x3 = _mm_alignr_epi8(x7, x6, 8); + x6 = _mm_alignr_epi8(z1, z0, 8); + x7 = _mm_alignr_epi8(z0, z1, 8); + + z0 = _mm_add_epi64(x0, x2); + z1 = _mm_add_epi64(x1, x3); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x6 = _mm_xor_si128(x6, z0); + x7 = _mm_xor_si128(x7, z1); + + z0 = _mm_add_epi64(x6, x0); + z1 = _mm_add_epi64(x7, x1); + z2 = _mm_srli_epi64(z0, 64-13); + z3 = _mm_srli_epi64(z1, 64-13); + z0 = _mm_slli_epi64(z0, 13); + z1 = _mm_slli_epi64(z1, 13); + x5 = _mm_xor_si128(x5, z2); + x4 = _mm_xor_si128(x4, z3); + x5 = _mm_xor_si128(x5, z0); + x4 = _mm_xor_si128(x4, z1); + + z0 = _mm_add_epi64(x5, x6); + z1 = _mm_add_epi64(x4, x7); + z2 = _mm_srli_epi64(z0, 64-39); + z3 = _mm_srli_epi64(z1, 64-39); + z0 = _mm_slli_epi64(z0, 39); + z1 = _mm_slli_epi64(z1, 39); + x2 = _mm_xor_si128(x2, z2); + x3 = _mm_xor_si128(x3, z3); + x2 = _mm_xor_si128(x2, z0); + x3 = _mm_xor_si128(x3, z1); + + z0 = _mm_add_epi64(x2, x5); + z1 = _mm_add_epi64(x3, x4); + z0 = _mm_shuffle_epi32(z0, _MM_SHUFFLE(2,3,0,1)); + z1 = _mm_shuffle_epi32(z1, _MM_SHUFFLE(2,3,0,1)); + x0 = _mm_xor_si128(x0, z0); + x1 = _mm_xor_si128(x1, z1); + + z0 = x2; + z1 = x3; + x2 = _mm_alignr_epi8(x6, x7, 8); + x3 = _mm_alignr_epi8(x7, x6, 8); + x6 = _mm_alignr_epi8(z1, z0, 8); + x7 = _mm_alignr_epi8(z0, z1, 8); + } + + x0 = _mm_add_epi64(x0, t0); + x1 = _mm_add_epi64(x1, t1); + x2 = _mm_add_epi64(x2, t2); + x3 = _mm_add_epi64(x3, t3); + x4 = _mm_add_epi64(x4, t4); + x5 = _mm_add_epi64(x5, t5); + x6 = _mm_add_epi64(x6, t6); + x7 = _mm_add_epi64(x7, t7); + + /* 4: Y_i = X */ + /* 6: B'[0..r-1] = Y_even */ + /* 6: B'[r..2r-1] = Y_odd */ + xmmp = (xmmi *)scrypt_block(Bout, (i / 2) + half); + xmmp[0] = x0; + xmmp[1] = x1; + xmmp[2] = x2; + xmmp[3] = x3; + xmmp[4] = x4; + xmmp[5] = x5; + xmmp[6] = x6; + xmmp[7] = x7; + } +} + +#endif + +#if defined(SCRYPT_SALSA64_SSSE3) + /* uses salsa64_core_tangle_sse2 */ + + #undef SCRYPT_MIX + #define SCRYPT_MIX "Salsa64/8-SSSE3" + #undef SCRYPT_SALSA64_INCLUDED + #define SCRYPT_SALSA64_INCLUDED +#endif diff --git a/scryptjane/scrypt-jane-mix_salsa64.h b/scryptjane/scrypt-jane-mix_salsa64.h new file mode 100644 index 000000000..2aec04f33 --- /dev/null +++ b/scryptjane/scrypt-jane-mix_salsa64.h @@ -0,0 +1,41 @@ +#if !defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_SALSA64_INCLUDED) + +#undef SCRYPT_MIX +#define SCRYPT_MIX "Salsa64/8 Ref" + +#undef SCRYPT_SALSA64_INCLUDED +#define SCRYPT_SALSA64_INCLUDED +#define SCRYPT_SALSA64_BASIC + +static void +salsa64_core_basic(uint64_t state[16]) { + const size_t rounds = 8; + uint64_t v[16], t; + size_t i; + + for (i = 0; i < 16; i++) v[i] = state[i]; + + #define G(a,b,c,d) \ + t = v[a]+v[d]; t = ROTL64(t, 32); v[b] ^= t; \ + t = v[b]+v[a]; t = ROTL64(t, 13); v[c] ^= t; \ + t = v[c]+v[b]; t = ROTL64(t, 39); v[d] ^= t; \ + t = v[d]+v[c]; t = ROTL64(t, 32); v[a] ^= t; \ + + for (i = 0; i < rounds; i += 2) { + G( 0, 4, 8,12); + G( 5, 9,13, 1); + G(10,14, 2, 6); + G(15, 3, 7,11); + G( 0, 1, 2, 3); + G( 5, 6, 7, 4); + G(10,11, 8, 9); + G(15,12,13,14); + } + + for (i = 0; i < 16; i++) state[i] += v[i]; + + #undef G +} + +#endif + diff --git a/scryptjane/scrypt-jane-pbkdf2.h b/scryptjane/scrypt-jane-pbkdf2.h index 711e3d633..761b812c5 100644 --- a/scryptjane/scrypt-jane-pbkdf2.h +++ b/scryptjane/scrypt-jane-pbkdf2.h @@ -40,7 +40,9 @@ scrypt_hmac_init(scrypt_hmac_state *st, const uint8_t *key, size_t keylen) { pad[i] ^= (0x5c ^ 0x36); scrypt_hash_update(&st->outer, pad, SCRYPT_HASH_BLOCK_SIZE); +#ifdef SCRYPT_PREVENT_STATE_LEAK scrypt_ensure_zero(pad, sizeof(pad)); +#endif } static void @@ -59,7 +61,9 @@ scrypt_hmac_finish(scrypt_hmac_state *st, scrypt_hash_digest mac) { scrypt_hash_update(&st->outer, innerhash, sizeof(innerhash)); scrypt_hash_finish(&st->outer, mac); +#ifdef SCRYPT_PREVENT_STATE_LEAK scrypt_ensure_zero(st, sizeof(*st)); +#endif } static void @@ -69,7 +73,7 @@ scrypt_pbkdf2(const uint8_t *password, size_t password_len, const uint8_t *salt, uint8_t be[4]; uint32_t i, j, blocks; uint64_t c; - + /* bytes must be <= (0xffffffff - (SCRYPT_HASH_DIGEST_SIZE - 1)), which they will always be under scrypt */ /* hmac(password, ...) */ @@ -105,8 +109,53 @@ scrypt_pbkdf2(const uint8_t *password, size_t password_len, const uint8_t *salt, bytes -= SCRYPT_HASH_DIGEST_SIZE; } +#ifdef SCRYPT_PREVENT_STATE_LEAK + scrypt_ensure_zero(ti, sizeof(ti)); + scrypt_ensure_zero(u, sizeof(u)); + scrypt_ensure_zero(&hmac_pw, sizeof(hmac_pw)); + scrypt_ensure_zero(&hmac_pw_salt, sizeof(hmac_pw_salt)); +#endif +} + +/* + * Special version where N = 1 + * - mikaelh + */ +static void +scrypt_pbkdf2_1(const uint8_t *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint8_t *out, size_t bytes) { + scrypt_hmac_state hmac_pw, hmac_pw_salt, work; + scrypt_hash_digest ti, u; + uint8_t be[4]; + uint32_t i, /*j,*/ blocks; + //uint64_t c; + + /* bytes must be <= (0xffffffff - (SCRYPT_HASH_DIGEST_SIZE - 1)), which they will always be under scrypt */ + + /* hmac(password, ...) */ + scrypt_hmac_init(&hmac_pw, password, password_len); + + /* hmac(password, salt...) */ + hmac_pw_salt = hmac_pw; + scrypt_hmac_update(&hmac_pw_salt, salt, salt_len); + + blocks = ((uint32_t)bytes + (SCRYPT_HASH_DIGEST_SIZE - 1)) / SCRYPT_HASH_DIGEST_SIZE; + for (i = 1; i <= blocks; i++) { + /* U1 = hmac(password, salt || be(i)) */ + U32TO8_BE(be, i); + work = hmac_pw_salt; + scrypt_hmac_update(&work, be, 4); + scrypt_hmac_finish(&work, ti); + memcpy(u, ti, sizeof(u)); + + memcpy(out, ti, (bytes > SCRYPT_HASH_DIGEST_SIZE) ? SCRYPT_HASH_DIGEST_SIZE : bytes); + out += SCRYPT_HASH_DIGEST_SIZE; + bytes -= SCRYPT_HASH_DIGEST_SIZE; + } + +#ifdef SCRYPT_PREVENT_STATE_LEAK scrypt_ensure_zero(ti, sizeof(ti)); scrypt_ensure_zero(u, sizeof(u)); scrypt_ensure_zero(&hmac_pw, sizeof(hmac_pw)); scrypt_ensure_zero(&hmac_pw_salt, sizeof(hmac_pw_salt)); +#endif } diff --git a/scryptjane/scrypt-jane-portable-x86.h b/scryptjane/scrypt-jane-portable-x86.h index 03282fa8a..d8325f059 100644 --- a/scryptjane/scrypt-jane-portable-x86.h +++ b/scryptjane/scrypt-jane-portable-x86.h @@ -45,6 +45,10 @@ #define X86_64USE_INTRINSIC #endif +#ifdef __AVX__ +#define X86_INTRINSIC_AVX +#endif + #if defined(COMPILER_GCC) && defined(CPU_X86_FORCE_INTRINSICS) #define X86_INTRINSIC #if defined(__SSE__) @@ -59,6 +63,15 @@ #if defined(__AVX__) #define X86_INTRINSIC_AVX #endif + + /* HACK - I want to use CPU_X86_FORCE_INTRINSICS with mingw64 so these need to be undefined - mikaelh */ + #undef X86_64ASM_SSSE3 + #undef X86_64ASM_AVX + #undef X86_64ASM_SSE2 + #undef X86ASM_AVX + #undef X86ASM_SSSE3 + #undef X86ASM_SSE2 + #undef X86ASM_SSE #endif /* only use simd on windows (or SSE2 on gcc)! */ @@ -80,6 +93,10 @@ #define X86_INTRINSIC_SSSE3 #include #endif + #if defined (X86_INTRINSIC_AVX) + #define X86_INTRINSIC_AVX + #include + #endif #endif @@ -115,11 +132,9 @@ } packedelem64; #endif -#if defined(X86_INTRINSIC_SSSE3) || defined(X86ASM_SSSE3) || defined(X86_64ASM_SSSE3) - const packedelem8 MM16 ssse3_rotr16_64bit = {{2,3,4,5,6,7,0,1,10,11,12,13,14,15,8,9}}; - const packedelem8 MM16 ssse3_rotl16_32bit = {{2,3,0,1,6,7,4,5,10,11,8,9,14,15,12,13}}; - const packedelem8 MM16 ssse3_rotl8_32bit = {{3,0,1,2,7,4,5,6,11,8,9,10,15,12,13,14}}; - const packedelem8 MM16 ssse3_endian_swap_64bit = {{7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8}}; +#if defined(X86_INTRINSIC_SSSE3) + static const packedelem8 MM16 ssse3_rotl16_32bit = {{2,3,0,1,6,7,4,5,10,11,8,9,14,15,12,13}}; + static const packedelem8 MM16 ssse3_rotl8_32bit = {{3,0,1,2,7,4,5,6,11,8,9,10,15,12,13,14}}; #endif /* @@ -130,7 +145,8 @@ a1(..) a2(.., ..) a3(.., .., ..) - a1(ret) + 64bit OR 0 paramters: a1(ret) + 32bit AND n parameters: aret(4n), eg aret(16) for 4 parameters asm_naked_fn_end(name) */ @@ -147,7 +163,8 @@ #define asm_align8 a1(ALIGN 8) #define asm_align16 a1(ALIGN 16) - #define asm_naked_fn_proto(type, fn) static NAKED type STDCALL fn + #define asm_calling_convention STDCALL + #define asm_naked_fn_proto(type, fn) static NAKED type asm_calling_convention fn #define asm_naked_fn(fn) { #define asm_naked_fn_end(fn) } #elif defined(COMPILER_GCC) @@ -156,6 +173,7 @@ #define GNU_AS3(x, y, z) #x ", " #y ", " #z ";\n" #define GNU_AS4(x, y, z, w) #x ", " #y ", " #z ", " #w ";\n" #define GNU_ASL(x) "\n" #x ":\n" + #define GNU_ASFN(x) "\n_" #x ":\n" #x ":\n" #define GNU_ASJ(x, y, z) #x " " #y #z ";" #define a1(x) GNU_AS1(x) @@ -167,9 +185,18 @@ #define asm_align8 a1(.align 8) #define asm_align16 a1(.align 16) - #define asm_naked_fn_proto(type, fn) extern type STDCALL fn - #define asm_naked_fn(fn) ; __asm__ (".intel_syntax noprefix;\n.text\n" asm_align16 GNU_ASL(fn) - #define asm_naked_fn_end(fn) ".att_syntax prefix;\n.type " #fn ",@function\n.size " #fn ",.-" #fn "\n" ); + #if defined(OS_WINDOWS) + #define asm_calling_convention CDECL + #define aret(n) a1(ret) + #define asm_naked_fn_end(fn) ".att_syntax prefix;\n" ); + #else + #define asm_calling_convention STDCALL + #define aret(n) a1(ret n) + #define asm_naked_fn_end(fn) ".att_syntax prefix;\n.type " #fn ",@function\n.size " #fn ",.-" #fn "\n" ); + #endif + #define asm_naked_fn_proto(type, fn) extern type asm_calling_convention fn + #define asm_naked_fn(fn) ; __asm__ (".intel_syntax noprefix;\n.text\n" asm_align16 GNU_ASFN(fn) + #define asm_gcc() __asm__ __volatile__(".intel_syntax noprefix;\n" #define asm_gcc_parms() ".att_syntax prefix;" #define asm_gcc_trashed() __asm__ __volatile__("" ::: @@ -361,4 +388,4 @@ get_top_cpuflag_desc(size_t flag) { #endif #endif -#endif /* defined(CPU_X86) || defined(CPU_X86_64) */ \ No newline at end of file +#endif /* defined(CPU_X86) || defined(CPU_X86_64) */ diff --git a/scryptjane/scrypt-jane-portable.h b/scryptjane/scrypt-jane-portable.h index 33c8c2cad..8a3ae9ef6 100644 --- a/scryptjane/scrypt-jane-portable.h +++ b/scryptjane/scrypt-jane-portable.h @@ -47,7 +47,6 @@ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4100) /* unreferenced formal parameter */ - #define _CRT_SECURE_NO_WARNINGS #include #include /* _rotl */ #include @@ -277,5 +276,13 @@ scrypt_ensure_zero(void *p, size_t len) { #endif } +#ifdef __arm__ + +static size_t detect_cpu(void) { + return 0; +} + +#endif + #include "scrypt-jane-portable-x86.h" diff --git a/scryptjane/scrypt-jane-romix-basic.h b/scryptjane/scrypt-jane-romix-basic.h index ca1df02d5..a464e04e1 100644 --- a/scryptjane/scrypt-jane-romix-basic.h +++ b/scryptjane/scrypt-jane-romix-basic.h @@ -4,12 +4,12 @@ typedef void (FASTCALL *scrypt_ROMixfn)(scrypt_mix_word_t *X/*[chunkWords]*/, sc #endif /* romix pre/post nop function */ -static void STDCALL +static void /* asm_calling_convention */ scrypt_romix_nop(scrypt_mix_word_t *blocks, size_t nblocks) { } /* romix pre/post endian conversion function */ -static void STDCALL +static void /* asm_calling_convention */ scrypt_romix_convert_endian(scrypt_mix_word_t *blocks, size_t nblocks) { #if !defined(CPU_LE) static const union { uint8_t b[2]; uint16_t w; } endian_test = {{1,0}}; @@ -24,8 +24,8 @@ scrypt_romix_convert_endian(scrypt_mix_word_t *blocks, size_t nblocks) { } /* chunkmix test function */ -typedef void (STDCALL *chunkmixfn)(scrypt_mix_word_t *Bout/*[chunkWords]*/, scrypt_mix_word_t *Bin/*[chunkWords]*/, scrypt_mix_word_t *Bxor/*[chunkWords]*/, uint32_t r); -typedef void (STDCALL *blockfixfn)(scrypt_mix_word_t *blocks, size_t nblocks); +typedef void (*chunkmixfn)(scrypt_mix_word_t *Bout/*[chunkWords]*/, scrypt_mix_word_t *Bin/*[chunkWords]*/, scrypt_mix_word_t *Bxor/*[chunkWords]*/, uint32_t r); +typedef void (*blockfixfn)(scrypt_mix_word_t *blocks, size_t nblocks); static int scrypt_test_mix_instance(chunkmixfn mixfn, blockfixfn prefn, blockfixfn postfn, const uint8_t expected[16]) { diff --git a/scryptjane/scrypt-jane-romix-template.h b/scryptjane/scrypt-jane-romix-template.h index 2fd7674ec..53236e4e2 100644 --- a/scryptjane/scrypt-jane-romix-template.h +++ b/scryptjane/scrypt-jane-romix-template.h @@ -17,7 +17,7 @@ 2*r: number of blocks in the chunk */ -static void STDCALL +static void /* asm_calling_convention */ SCRYPT_CHUNKMIX_FN(scrypt_mix_word_t *Bout/*[chunkWords]*/, scrypt_mix_word_t *Bin/*[chunkWords]*/, scrypt_mix_word_t *Bxor/*[chunkWords]*/, uint32_t r) { scrypt_mix_word_t MM16 X[SCRYPT_BLOCK_WORDS], *block; uint32_t i, j, blocksPerChunk = r * 2, half = 0; @@ -107,6 +107,67 @@ SCRYPT_ROMIX_FN(scrypt_mix_word_t *X/*[chunkWords]*/, scrypt_mix_word_t *Y/*[chu SCRYPT_ROMIX_UNTANGLE_FN(X, r * 2); } +/* + * Special version with hard-coded r = 1 + * - mikaelh + */ +static void NOINLINE FASTCALL +scrypt_ROMix_1(scrypt_mix_word_t *X/*[chunkWords]*/, scrypt_mix_word_t *Y/*[chunkWords]*/, scrypt_mix_word_t *V/*[N * chunkWords]*/, uint32_t N) { + const uint32_t r = 1; + uint32_t i, j, chunkWords = SCRYPT_BLOCK_WORDS * r * 2; + scrypt_mix_word_t *block = V; + + SCRYPT_ROMIX_TANGLE_FN(X, r * 2); + + /* 1: X = B */ + /* implicit */ + + /* 2: for i = 0 to N - 1 do */ + memcpy(block, X, chunkWords * sizeof(scrypt_mix_word_t)); + for (i = 0; i < N - 1; i++, block += chunkWords) { + /* 3: V_i = X */ + /* 4: X = H(X) */ +#ifdef SCRYPT_CHUNKMIX_1_FN + SCRYPT_CHUNKMIX_1_FN(block + chunkWords, block); +#else + SCRYPT_CHUNKMIX_FN(block + chunkWords, block, NULL, r); +#endif + } +#ifdef SCRYPT_CHUNKMIX_1_FN + SCRYPT_CHUNKMIX_1_FN(X, block); +#else + SCRYPT_CHUNKMIX_FN(X, block, NULL, r); +#endif + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j = Integerify(X) % N */ + j = X[chunkWords - SCRYPT_BLOCK_WORDS] & (N - 1); + + /* 8: X = H(Y ^ V_j) */ +#ifdef SCRYPT_CHUNKMIX_1_XOR_FN + SCRYPT_CHUNKMIX_1_XOR_FN(Y, X, scrypt_item(V, j, chunkWords)); +#else + SCRYPT_CHUNKMIX_FN(Y, X, scrypt_item(V, j, chunkWords), r); +#endif + + /* 7: j = Integerify(Y) % N */ + j = Y[chunkWords - SCRYPT_BLOCK_WORDS] & (N - 1); + + /* 8: X = H(Y ^ V_j) */ +#ifdef SCRYPT_CHUNKMIX_1_XOR_FN + SCRYPT_CHUNKMIX_1_XOR_FN(X, Y, scrypt_item(V, j, chunkWords)); +#else + SCRYPT_CHUNKMIX_FN(X, Y, scrypt_item(V, j, chunkWords), r); +#endif + } + + /* 10: B' = X */ + /* implicit */ + + SCRYPT_ROMIX_UNTANGLE_FN(X, r * 2); +} + #endif /* !defined(SCRYPT_CHOOSE_COMPILETIME) || !defined(SCRYPT_HAVE_ROMIX) */ diff --git a/scryptjane/scrypt-jane-salsa.h b/scryptjane/scrypt-jane-salsa.h index 0c1604bad..76f3da630 100644 --- a/scryptjane/scrypt-jane-salsa.h +++ b/scryptjane/scrypt-jane-salsa.h @@ -64,13 +64,16 @@ scrypt_getROMix() { #if defined(SCRYPT_TEST_SPEED) static size_t available_implementations() { + size_t cpuflags = detect_cpu(); size_t flags = 0; #if defined(SCRYPT_SALSA_AVX) + if (cpuflags & cpu_avx) flags |= cpu_avx; #endif #if defined(SCRYPT_SALSA_SSE2) + if (cpuflags & cpu_sse2) flags |= cpu_sse2; #endif diff --git a/scryptjane/scrypt-jane-salsa64.h b/scryptjane/scrypt-jane-salsa64.h new file mode 100644 index 000000000..ecc87f596 --- /dev/null +++ b/scryptjane/scrypt-jane-salsa64.h @@ -0,0 +1,133 @@ +#define SCRYPT_MIX_BASE "Salsa64/8" + +typedef uint64_t scrypt_mix_word_t; + +#define SCRYPT_WORDTO8_LE U64TO8_LE +#define SCRYPT_WORD_ENDIAN_SWAP U64_SWAP + +#define SCRYPT_BLOCK_BYTES 128 +#define SCRYPT_BLOCK_WORDS (SCRYPT_BLOCK_BYTES / sizeof(scrypt_mix_word_t)) + +/* must have these here in case block bytes is ever != 64 */ +#include "scrypt-jane-romix-basic.h" + +#include "scrypt-jane-mix_salsa64-avx.h" +#include "scrypt-jane-mix_salsa64-ssse3.h" +#include "scrypt-jane-mix_salsa64-sse2.h" +#include "scrypt-jane-mix_salsa64.h" + +#if defined(SCRYPT_SALSA64_AVX) + #define SCRYPT_CHUNKMIX_FN scrypt_ChunkMix_avx + #define SCRYPT_ROMIX_FN scrypt_ROMix_avx + #define SCRYPT_ROMIX_TANGLE_FN salsa64_core_tangle_sse2 + #define SCRYPT_ROMIX_UNTANGLE_FN salsa64_core_tangle_sse2 + #include "scrypt-jane-romix-template.h" +#endif + +#if defined(SCRYPT_SALSA64_SSSE3) + #define SCRYPT_CHUNKMIX_FN scrypt_ChunkMix_ssse3 + #define SCRYPT_ROMIX_FN scrypt_ROMix_ssse3 + #define SCRYPT_ROMIX_TANGLE_FN salsa64_core_tangle_sse2 + #define SCRYPT_ROMIX_UNTANGLE_FN salsa64_core_tangle_sse2 + #include "scrypt-jane-romix-template.h" +#endif + +#if defined(SCRYPT_SALSA64_SSE2) + #define SCRYPT_CHUNKMIX_FN scrypt_ChunkMix_sse2 + #define SCRYPT_ROMIX_FN scrypt_ROMix_sse2 + #define SCRYPT_ROMIX_TANGLE_FN salsa64_core_tangle_sse2 + #define SCRYPT_ROMIX_UNTANGLE_FN salsa64_core_tangle_sse2 + #include "scrypt-jane-romix-template.h" +#endif + +/* cpu agnostic */ +#define SCRYPT_ROMIX_FN scrypt_ROMix_basic +#define SCRYPT_MIX_FN salsa64_core_basic +#define SCRYPT_ROMIX_TANGLE_FN scrypt_romix_convert_endian +#define SCRYPT_ROMIX_UNTANGLE_FN scrypt_romix_convert_endian +#include "scrypt-jane-romix-template.h" + +#if !defined(SCRYPT_CHOOSE_COMPILETIME) +static scrypt_ROMixfn +scrypt_getROMix() { + size_t cpuflags = detect_cpu(); + +#if defined(SCRYPT_SALSA64_AVX) + if (cpuflags & cpu_avx) + return scrypt_ROMix_avx; + else +#endif + +#if defined(SCRYPT_SALSA64_SSSE3) + if (cpuflags & cpu_ssse3) + return scrypt_ROMix_ssse3; + else +#endif + +#if defined(SCRYPT_SALSA64_SSE2) + if (cpuflags & cpu_sse2) + return scrypt_ROMix_sse2; + else +#endif + + return scrypt_ROMix_basic; +} +#endif + + +#if defined(SCRYPT_TEST_SPEED) +static size_t +available_implementations() { + size_t cpuflags = detect_cpu(); + size_t flags = 0; + +#if defined(SCRYPT_SALSA64_AVX) + if (cpuflags & cpu_avx) + flags |= cpu_avx; +#endif + +#if defined(SCRYPT_SALSA64_SSSE3) + if (cpuflags & cpu_ssse3) + flags |= cpu_ssse3; +#endif + +#if defined(SCRYPT_SALSA64_SSE2) + if (cpuflags & cpu_sse2) + flags |= cpu_sse2; +#endif + + return flags; +} +#endif + +static int +scrypt_test_mix() { + static const uint8_t expected[16] = { + 0xf8,0x92,0x9b,0xf8,0xcc,0x1d,0xce,0x2e,0x13,0x82,0xac,0x96,0xb2,0x6c,0xee,0x2c, + }; + + int ret = 1; + size_t cpuflags = detect_cpu(); + +#if defined(SCRYPT_SALSA64_AVX) + if (cpuflags & cpu_avx) + ret &= scrypt_test_mix_instance(scrypt_ChunkMix_avx, salsa64_core_tangle_sse2, salsa64_core_tangle_sse2, expected); +#endif + +#if defined(SCRYPT_SALSA64_SSSE3) + if (cpuflags & cpu_ssse3) + ret &= scrypt_test_mix_instance(scrypt_ChunkMix_ssse3, salsa64_core_tangle_sse2, salsa64_core_tangle_sse2, expected); +#endif + +#if defined(SCRYPT_SALSA64_SSE2) + if (cpuflags & cpu_sse2) + ret &= scrypt_test_mix_instance(scrypt_ChunkMix_sse2, salsa64_core_tangle_sse2, salsa64_core_tangle_sse2, expected); +#endif + +#if defined(SCRYPT_SALSA64_BASIC) + ret &= scrypt_test_mix_instance(scrypt_ChunkMix_basic, scrypt_romix_convert_endian, scrypt_romix_convert_endian, expected); +#endif + + return ret; +} + diff --git a/scryptjane/scrypt-jane-test-vectors.h b/scryptjane/scrypt-jane-test-vectors.h index a1e4c619a..d7740917e 100644 --- a/scryptjane/scrypt-jane-test-vectors.h +++ b/scryptjane/scrypt-jane-test-vectors.h @@ -3,9 +3,14 @@ typedef struct scrypt_test_setting_t { uint8_t Nfactor, rfactor, pfactor; } scrypt_test_setting; +/* + * I'm hardcoding the values of p and r, which means they can't be tested + * anymore. A new test case with a different value for N should maybe be added. + * - mikaelh + */ static const scrypt_test_setting post_settings[] = { {"", "", 3, 0, 0}, - {"password", "NaCl", 9, 3, 4}, +// {"password", "NaCl", 9, 3, 4}, {0} }; diff --git a/sha3/gost_streebog.c b/sha3/gost_streebog.c new file mode 100644 index 000000000..1689426bd --- /dev/null +++ b/sha3/gost_streebog.c @@ -0,0 +1,1023 @@ +/* GOST-R Streebog hash function for sib algo SibCoin */ + +#include +#include +#include +#include + +#include "gost_streebog.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +//-------------------------------------------------------------------------------------------- +// +// streebog implementation +// +//-------------------------------------------------------------------------------------------- + + +// Tables for function F +static const sph_u64 TG[8][256] = {{ + 0xE6F87E5C5B711FD0,0x258377800924FA16,0xC849E07E852EA4A8,0x5B4686A18F06C16A, + 0x0B32E9A2D77B416E,0xABDA37A467815C66,0xF61796A81A686676,0xF5DC0B706391954B, + 0x4862F38DB7E64BF1,0xFF5C629A68BD85C5,0xCB827DA6FCD75795,0x66D36DAF69B9F089, + 0x356C9F74483D83B0,0x7CBCECB1238C99A1,0x36A702AC31C4708D,0x9EB6A8D02FBCDFD6, + 0x8B19FA51E5B3AE37,0x9CCFB5408A127D0B,0xBC0C78B508208F5A,0xE533E3842288ECED, + 0xCEC2C7D377C15FD2,0xEC7817B6505D0F5E,0xB94CC2C08336871D,0x8C205DB4CB0B04AD, + 0x763C855B28A0892F,0x588D1B79F6FF3257,0x3FECF69E4311933E,0x0FC0D39F803A18C9, + 0xEE010A26F5F3AD83,0x10EFE8F4411979A6,0x5DCDA10C7DE93A10,0x4A1BEE1D1248E92C, + 0x53BFF2DB21847339,0xB4F50CCFA6A23D09,0x5FB4BC9CD84798CD,0xE88A2D8B071C56F9, + 0x7F7771695A756A9C,0xC5F02E71A0BA1EBC,0xA663F9AB4215E672,0x2EB19E22DE5FBB78, + 0x0DB9CE0F2594BA14,0x82520E6397664D84,0x2F031E6A0208EA98,0x5C7F2144A1BE6BF0, + 0x7A37CB1CD16362DB,0x83E08E2B4B311C64,0xCF70479BAB960E32,0x856BA986B9DEE71E, + 0xB5478C877AF56CE9,0xB8FE42885F61D6FD,0x1BDD0156966238C8,0x622157923EF8A92E, + 0xFC97FF42114476F8,0x9D7D350856452CEB,0x4C90C9B0E0A71256,0x2308502DFBCB016C, + 0x2D7A03FAA7A64845,0xF46E8B38BFC6C4AB,0xBDBEF8FDD477DEBA,0x3AAC4CEBC8079B79, + 0xF09CB105E8879D0C,0x27FA6A10AC8A58CB,0x8960E7C1401D0CEA,0x1A6F811E4A356928, + 0x90C4FB0773D196FF,0x43501A2F609D0A9F,0xF7A516E0C63F3796,0x1CE4A6B3B8DA9252, + 0x1324752C38E08A9B,0xA5A864733BEC154F,0x2BF124575549B33F,0xD766DB15440DC5C7, + 0xA7D179E39E42B792,0xDADF151A61997FD3,0x86A0345EC0271423,0x38D5517B6DA939A4, + 0x6518F077104003B4,0x02791D90A5AEA2DD,0x88D267899C4A5D0A,0x930F66DF0A2865C2, + 0x4EE9D4204509B08B,0x325538916685292A,0x412907BFC533A842,0xB27E2B62544DC673, + 0x6C5304456295E007,0x5AF406E95351908A,0x1F2F3B6BC123616F,0xC37B09DC5255E5C6, + 0x3967D133B1FE6844,0x298839C7F0E711E2,0x409B87F71964F9A2,0xE938ADC3DB4B0719, + 0x0C0B4E47F9C3EBF4,0x5534D576D36B8843,0x4610A05AEB8B02D8,0x20C3CDF58232F251, + 0x6DE1840DBEC2B1E7,0xA0E8DE06B0FA1D08,0x7B854B540D34333B,0x42E29A67BCCA5B7F, + 0xD8A6088AC437DD0E,0xC63BB3A9D943ED81,0x21714DBD5E65A3B1,0x6761EDE7B5EEA169, + 0x2431F7C8D573ABF6,0xD51FC685E1A3671A,0x5E063CD40410C92D,0x283AB98F2CB04002, + 0x8FEBC06CB2F2F790,0x17D64F116FA1D33C,0xE07359F1A99EE4AA,0x784ED68C74CDC006, + 0x6E2A19D5C73B42DA,0x8712B4161C7045C3,0x371582E4ED93216D,0xACE390414939F6FC, + 0x7EC5F12186223B7C,0xC0B094042BAC16FB,0xF9D745379A527EBF,0x737C3F2EA3B68168, + 0x33E7B8D9BAD278CA,0xA9A32A34C22FFEBB,0xE48163CCFEDFBD0D,0x8E5940246EA5A670, + 0x51C6EF4B842AD1E4,0x22BAD065279C508C,0xD91488C218608CEE,0x319EA5491F7CDA17, + 0xD394E128134C9C60,0x094BF43272D5E3B3,0x9BF612A5A4AAD791,0xCCBBDA43D26FFD0F, + 0x34DE1F3C946AD250,0x4F5B5468995EE16B,0xDF9FAF6FEA8F7794,0x2648EA5870DD092B, + 0xBFC7E56D71D97C67,0xDDE6B2FF4F21D549,0x3C276B463AE86003,0x91767B4FAF86C71F, + 0x68A13E7835D4B9A0,0xB68C115F030C9FD4,0x141DD2C916582001,0x983D8F7DDD5324AC, + 0x64AA703FCC175254,0xC2C989948E02B426,0x3E5E76D69F46C2DE,0x50746F03587D8004, + 0x45DB3D829272F1E5,0x60584A029B560BF3,0xFBAE58A73FFCDC62,0xA15A5E4E6CAD4CE8, + 0x4BA96E55CE1FB8CC,0x08F9747AAE82B253,0xC102144CF7FB471B,0x9F042898F3EB8E36, + 0x068B27ADF2EFFB7A,0xEDCA97FE8C0A5EBE,0x778E0513F4F7D8CF,0x302C2501C32B8BF7, + 0x8D92DDFC175C554D,0xF865C57F46052F5F,0xEAF3301BA2B2F424,0xAA68B7ECBBD60D86, + 0x998F0F350104754C,0x0000000000000000,0xF12E314D34D0CCEC,0x710522BE061823B5, + 0xAF280D9930C005C1,0x97FD5CE25D693C65,0x19A41CC633CC9A15,0x95844172F8C79EB8, + 0xDC5432B7937684A9,0x9436C13A2490CF58,0x802B13F332C8EF59,0xC442AE397CED4F5C, + 0xFA1CD8EFE3AB8D82,0xF2E5AC954D293FD1,0x6AD823E8907A1B7D,0x4D2249F83CF043B6, + 0x03CB9DD879F9F33D,0xDE2D2F2736D82674,0x2A43A41F891EE2DF,0x6F98999D1B6C133A, + 0xD4AD46CD3DF436FA,0xBB35DF50269825C0,0x964FDCAA813E6D85,0xEB41B0537EE5A5C4, + 0x0540BA758B160847,0xA41AE43BE7BB44AF,0xE3B8C429D0671797,0x819993BBEE9FBEB9, + 0xAE9A8DD1EC975421,0xF3572CDD917E6E31,0x6393D7DAE2AFF8CE,0x47A2201237DC5338, + 0xA32343DEC903EE35,0x79FC56C4A89A91E6,0x01B28048DC5751E0,0x1296F564E4B7DB7B, + 0x75F7188351597A12,0xDB6D9552BDCE2E33,0x1E9DBB231D74308F,0x520D7293FDD322D9, + 0xE20A44610C304677,0xFEEEE2D2B4EAD425,0xCA30FDEE20800675,0x61EACA4A47015A13, + 0xE74AFE1487264E30,0x2CC883B27BF119A5,0x1664CF59B3F682DC,0xA811AA7C1E78AF5B, + 0x1D5626FB648DC3B2,0xB73E9117DF5BCE34,0xD05F7CF06AB56F5D,0xFD257F0ACD132718, + 0x574DC8E676C52A9E,0x0739A7E52EB8AA9A,0x5486553E0F3CD9A3,0x56FF48AEAA927B7E, + 0xBE756525AD8E2D87,0x7D0E6CF9FFDBC841,0x3B1ECCA31450CA99,0x6913BE30E983E840, + 0xAD511009956EA71C,0xB1B5B6BA2DB4354E,0x4469BDCA4E25A005,0x15AF5281CA0F71E1, + 0x744598CB8D0E2BF2,0x593F9B312AA863B7,0xEFB38A6E29A4FC63,0x6B6AA3A04C2D4A9D, + 0x3D95EB0EE6BF31E3,0xA291C3961554BFD5,0x18169C8EEF9BCBF5,0x115D68BC9D4E2846, + 0xBA875F18FACF7420,0xD1EDFCB8B6E23EBD,0xB00736F2F1E364AE,0x84D929CE6589B6FE, + 0x70B7A2F6DA4F7255,0x0E7253D75C6D4929,0x04F23A3D574159A7,0x0A8069EA0B2C108E, + 0x49D073C56BB11A11,0x8AAB7A1939E4FFD7,0xCD095A0B0E38ACEF,0xC9FB60365979F548, + 0x92BDE697D67F3422,0xC78933E10514BC61,0xE1C1D9B975C9B54A,0xD2266160CF1BCD80, + 0x9A4492ED78FD8671,0xB3CCAB2A881A9793,0x72CEBF667FE1D088,0xD6D45B5D985A9427 +},{ + 0xC811A8058C3F55DE,0x65F5B43196B50619,0xF74F96B1D6706E43,0x859D1E8BCB43D336, + 0x5AAB8A85CCFA3D84,0xF9C7BF99C295FCFD,0xA21FD5A1DE4B630F,0xCDB3EF763B8B456D, + 0x803F59F87CF7C385,0xB27C73BE5F31913C,0x98E3AC6633B04821,0xBF61674C26B8F818, + 0x0FFBC995C4C130C8,0xAAA0862010761A98,0x6057F342210116AA,0xF63C760C0654CC35, + 0x2DDB45CC667D9042,0xBCF45A964BD40382,0x68E8A0C3EF3C6F3D,0xA7BD92D269FF73BC, + 0x290AE20201ED2287,0xB7DE34CDE885818F,0xD901EEA7DD61059B,0xD6FA273219A03553, + 0xD56F1AE874CCCEC9,0xEA31245C2E83F554,0x7034555DA07BE499,0xCE26D2AC56E7BEF7, + 0xFD161857A5054E38,0x6A0E7DA4527436D1,0x5BD86A381CDE9FF2,0xCAF7756231770C32, + 0xB09AAED9E279C8D0,0x5DEF1091C60674DB,0x111046A2515E5045,0x23536CE4729802FC, + 0xC50CBCF7F5B63CFA,0x73A16887CD171F03,0x7D2941AFD9F28DBD,0x3F5E3EB45A4F3B9D, + 0x84EEFE361B677140,0x3DB8E3D3E7076271,0x1A3A28F9F20FD248,0x7EBC7C75B49E7627, + 0x74E5F293C7EB565C,0x18DCF59E4F478BA4,0x0C6EF44FA9ADCB52,0xC699812D98DAC760, + 0x788B06DC6E469D0E,0xFC65F8EA7521EC4E,0x30A5F7219E8E0B55,0x2BEC3F65BCA57B6B, + 0xDDD04969BAF1B75E,0x99904CDBE394EA57,0x14B201D1E6EA40F6,0xBBB0C08241284ADD, + 0x50F20463BF8F1DFF,0xE8D7F93B93CBACB8,0x4D8CB68E477C86E8,0xC1DD1B3992268E3F, + 0x7C5AA11209D62FCB,0x2F3D98ABDB35C9AE,0x671369562BFD5FF5,0x15C1E16C36CEE280, + 0x1D7EB2EDF8F39B17,0xDA94D37DB00DFE01,0x877BC3EC760B8ADA,0xCB8495DFE153AE44, + 0x05A24773B7B410B3,0x12857B783C32ABDF,0x8EB770D06812513B,0x536739B9D2E3E665, + 0x584D57E271B26468,0xD789C78FC9849725,0xA935BBFA7D1AE102,0x8B1537A3DFA64188, + 0xD0CD5D9BC378DE7A,0x4AC82C9A4D80CFB7,0x42777F1B83BDB620,0x72D2883A1D33BD75, + 0x5E7A2D4BAB6A8F41,0xF4DAAB6BBB1C95D9,0x905CFFE7FD8D31B6,0x83AA6422119B381F, + 0xC0AEFB8442022C49,0xA0F908C663033AE3,0xA428AF0804938826,0xADE41C341A8A53C7, + 0xAE7121EE77E6A85D,0xC47F5C4A25929E8C,0xB538E9AA55CDD863,0x06377AA9DAD8EB29, + 0xA18AE87BB3279895,0x6EDFDA6A35E48414,0x6B7D9D19825094A7,0xD41CFA55A4E86CBF, + 0xE5CAEDC9EA42C59C,0xA36C351C0E6FC179,0x5181E4DE6FABBF89,0xFFF0C530184D17D4, + 0x9D41EB1584045892,0x1C0D525028D73961,0xF178EC180CA8856A,0x9A0571018EF811CD, + 0x4091A27C3EF5EFCC,0x19AF15239F6329D2,0x347450EFF91EB990,0xE11B4A078DD27759, + 0xB9561DE5FC601331,0x912F1F5A2DA993C0,0x1654DCB65BA2191A,0x3E2DDE098A6B99EB, + 0x8A66D71E0F82E3FE,0x8C51ADB7D55A08D7,0x4533E50F8941FF7F,0x02E6DD67BD4859EC, + 0xE068AABA5DF6D52F,0xC24826E3FF4A75A5,0x6C39070D88ACDDF8,0x6486548C4691A46F, + 0xD1BEBD26135C7C0C,0xB30F93038F15334A,0x82D9849FC1BF9A69,0x9C320BA85420FAE4, + 0xFA528243AFF90767,0x9ED4D6CFE968A308,0xB825FD582C44B147,0x9B7691BC5EDCB3BB, + 0xC7EA619048FE6516,0x1063A61F817AF233,0x47D538683409A693,0x63C2CE984C6DED30, + 0x2A9FDFD86C81D91D,0x7B1E3B06032A6694,0x666089EBFBD9FD83,0x0A598EE67375207B, + 0x07449A140AFC495F,0x2CA8A571B6593234,0x1F986F8A45BBC2FB,0x381AA4A050B372C2, + 0x5423A3ADD81FAF3A,0x17273C0B8B86BB6C,0xFE83258DC869B5A2,0x287902BFD1C980F1, + 0xF5A94BD66B3837AF,0x88800A79B2CABA12,0x55504310083B0D4C,0xDF36940E07B9EEB2, + 0x04D1A7CE6790B2C5,0x612413FFF125B4DC,0x26F12B97C52C124F,0x86082351A62F28AC, + 0xEF93632F9937E5E7,0x3507B052293A1BE6,0xE72C30AE570A9C70,0xD3586041AE1425E0, + 0xDE4574B3D79D4CC4,0x92BA228040C5685A,0xF00B0CA5DC8C271C,0xBE1287F1F69C5A6E, + 0xF39E317FB1E0DC86,0x495D114020EC342D,0x699B407E3F18CD4B,0xDCA3A9D46AD51528, + 0x0D1D14F279896924,0x0000000000000000,0x593EB75FA196C61E,0x2E4E78160B116BD8, + 0x6D4AE7B058887F8E,0xE65FD013872E3E06,0x7A6DDBBBD30EC4E2,0xAC97FC89CAAEF1B1, + 0x09CCB33C1E19DBE1,0x89F3EAC462EE1864,0x7770CF49AA87ADC6,0x56C57ECA6557F6D6, + 0x03953DDA6D6CFB9A,0x36928D884456E07C,0x1EEB8F37959F608D,0x31D6179C4EAAA923, + 0x6FAC3AD7E5C02662,0x43049FA653991456,0xABD3669DC052B8EE,0xAF02C153A7C20A2B, + 0x3CCB036E3723C007,0x93C9C23D90E1CA2C,0xC33BC65E2F6ED7D3,0x4CFF56339758249E, + 0xB1E94E64325D6AA6,0x37E16D359472420A,0x79F8E661BE623F78,0x5214D90402C74413, + 0x482EF1FDF0C8965B,0x13F69BC5EC1609A9,0x0E88292814E592BE,0x4E198B542A107D72, + 0xCCC00FCBEBAFE71B,0x1B49C844222B703E,0x2564164DA840E9D5,0x20C6513E1FF4F966, + 0xBAC3203F910CE8AB,0xF2EDD1C261C47EF0,0x814CB945ACD361F3,0x95FEB8944A392105, + 0x5C9CF02C1622D6AD,0x971865F3F77178E9,0xBD87BA2B9BF0A1F4,0x444005B259655D09, + 0xED75BE48247FBC0B,0x7596122E17CFF42A,0xB44B091785E97A15,0x966B854E2755DA9F, + 0xEEE0839249134791,0x32432A4623C652B9,0xA8465B47AD3E4374,0xF8B45F2412B15E8B, + 0x2417F6F078644BA3,0xFB2162FE7FDDA511,0x4BBBCC279DA46DC1,0x0173E0BDD024A276, + 0x22208C59A2BCA08A,0x8FC4906DB836F34D,0xE4B90D743A6667EA,0x7147B5E0705F46EF, + 0x2782CB2A1508B039,0xEC065EF5F45B1E7D,0x21B5B183CFD05B10,0xDBE733C060295C77, + 0x9FA73672394C017E,0xCF55321186C31C81,0xD8720E1A0D45A7ED,0x3B8F997A3DDF8958, + 0x3AFC79C7EDFB2B2E,0xE9A4198643EF0ECE,0x5F09CDF67B4E2D37,0x4F6A6BE9FA34DF04, + 0xB6ADD47038A123F9,0x8D224D0A057EAAA1,0xC96248B85C1BF7A8,0xE3FD9760309A2EB5, + 0x0B2A6E5BA351820D,0xEB42C4E1FEA75722,0x948D58299A1D8373,0x7FCF9CC864BAD451, + 0xA55B4FB5D4B72A50,0x08BF5381CE3D7997,0x46A6D8D5E42D04E5,0xD22B80FC7E308796, + 0x57B69E77B57354A0,0x3969441D8097D0B4,0x3330CAFBF3E2F0CF,0xE28E77DDE0BE8CC3, + 0x62B12E259C494F46,0xA6CE726FB9DBD1CA,0x41E242C1EED14DBA,0x76032FF47AA30FB0 +},{ + 0x45B268A93ACDE4CC,0xAF7F0BE884549D08,0x048354B3C1468263,0x925435C2C80EFED2, + 0xEE4E37F27FDFFBA7,0x167A33920C60F14D,0xFB123B52EA03E584,0x4A0CAB53FDBB9007, + 0x9DEAF6380F788A19,0xCB48EC558F0CB32A,0xB59DC4B2D6FEF7E0,0xDCDBCA22F4F3ECB6, + 0x11DF5813549A9C40,0xE33FDEDF568ACED3,0xA0C1C8124322E9C3,0x07A56B8158FA6D0D, + 0x77279579B1E1F3DD,0xD9B18B74422AC004,0xB8EC2D9FFFABC294,0xF4ACF8A82D75914F, + 0x7BBF69B1EF2B6878,0xC4F62FAF487AC7E1,0x76CE809CC67E5D0C,0x6711D88F92E4C14C, + 0x627B99D9243DEDFE,0x234AA5C3DFB68B51,0x909B1F15262DBF6D,0x4F66EA054B62BCB5, + 0x1AE2CF5A52AA6AE8,0xBEA053FBD0CE0148,0xED6808C0E66314C9,0x43FE16CD15A82710, + 0xCD049231A06970F6,0xE7BC8A6C97CC4CB0,0x337CE835FCB3B9C0,0x65DEF2587CC780F3, + 0x52214EDE4132BB50,0x95F15E4390F493DF,0x870839625DD2E0F1,0x41313C1AFB8B66AF, + 0x91720AF051B211BC,0x477D427ED4EEA573,0x2E3B4CEEF6E3BE25,0x82627834EB0BCC43, + 0x9C03E3DD78E724C8,0x2877328AD9867DF9,0x14B51945E243B0F2,0x574B0F88F7EB97E2, + 0x88B6FA989AA4943A,0x19C4F068CB168586,0x50EE6409AF11FAEF,0x7DF317D5C04EABA4, + 0x7A567C5498B4C6A9,0xB6BBFB804F42188E,0x3CC22BCF3BC5CD0B,0xD04336EAAA397713, + 0xF02FAC1BEC33132C,0x2506DBA7F0D3488D,0xD7E65D6BF2C31A1E,0x5EB9B2161FF820F5, + 0x842E0650C46E0F9F,0x716BEB1D9E843001,0xA933758CAB315ED4,0x3FE414FDA2792265, + 0x27C9F1701EF00932,0x73A4C1CA70A771BE,0x94184BA6E76B3D0E,0x40D829FF8C14C87E, + 0x0FBEC3FAC77674CB,0x3616A9634A6A9572,0x8F139119C25EF937,0xF545ED4D5AEA3F9E, + 0xE802499650BA387B,0x6437E7BD0B582E22,0xE6559F89E053E261,0x80AD52E305288DFC, + 0x6DC55A23E34B9935,0xDE14E0F51AD0AD09,0xC6390578A659865E,0x96D7617109487CB1, + 0xE2D6CB3A21156002,0x01E915E5779FAED1,0xADB0213F6A77DCB7,0x9880B76EB9A1A6AB, + 0x5D9F8D248644CF9B,0xFD5E4536C5662658,0xF1C6B9FE9BACBDFD,0xEACD6341BE9979C4, + 0xEFA7221708405576,0x510771ECD88E543E,0xC2BA51CB671F043D,0x0AD482AC71AF5879, + 0xFE787A045CDAC936,0xB238AF338E049AED,0xBD866CC94972EE26,0x615DA6EBBD810290, + 0x3295FDD08B2C1711,0xF834046073BF0AEA,0xF3099329758FFC42,0x1CAEB13E7DCFA934, + 0xBA2307481188832B,0x24EFCE42874CE65C,0x0E57D61FB0E9DA1A,0xB3D1BAD6F99B343C, + 0xC0757B1C893C4582,0x2B510DB8403A9297,0x5C7698C1F1DB614A,0x3E0D0118D5E68CB4, + 0xD60F488E855CB4CF,0xAE961E0DF3CB33D9,0x3A8E55AB14A00ED7,0x42170328623789C1, + 0x838B6DD19C946292,0x895FEF7DED3B3AEB,0xCFCBB8E64E4A3149,0x064C7E642F65C3DC, + 0x3D2B3E2A4C5A63DA,0x5BD3F340A9210C47,0xB474D157A1615931,0xAC5934DA1DE87266, + 0x6EE365117AF7765B,0xC86ED36716B05C44,0x9BA6885C201D49C5,0xB905387A88346C45, + 0x131072C4BAB9DDFF,0xBF49461EA751AF99,0xD52977BC1CE05BA1,0xB0F785E46027DB52, + 0x546D30BA6E57788C,0x305AD707650F56AE,0xC987C682612FF295,0xA5AB8944F5FBC571, + 0x7ED528E759F244CA,0x8DDCBBCE2C7DB888,0xAA154ABE328DB1BA,0x1E619BE993ECE88B, + 0x09F2BD9EE813B717,0x7401AA4B285D1CB3,0x21858F143195CAEE,0x48C381841398D1B8, + 0xFCB750D3B2F98889,0x39A86A998D1CE1B9,0x1F888E0CE473465A,0x7899568376978716, + 0x02CF2AD7EE2341BF,0x85C713B5B3F1A14E,0xFF916FE12B4567E7,0x7C1A0230B7D10575, + 0x0C98FCC85ECA9BA5,0xA3E7F720DA9E06AD,0x6A6031A2BBB1F438,0x973E74947ED7D260, + 0x2CF4663918C0FF9A,0x5F50A7F368678E24,0x34D983B4A449D4CD,0x68AF1B755592B587, + 0x7F3C3D022E6DEA1B,0xABFC5F5B45121F6B,0x0D71E92D29553574,0xDFFDF5106D4F03D8, + 0x081BA87B9F8C19C6,0xDB7EA1A3AC0981BB,0xBBCA12AD66172DFA,0x79704366010829C7, + 0x179326777BFF5F9C,0x0000000000000000,0xEB2476A4C906D715,0x724DD42F0738DF6F, + 0xB752EE6538DDB65F,0x37FFBC863DF53BA3,0x8EFA84FCB5C157E6,0xE9EB5C73272596AA, + 0x1B0BDABF2535C439,0x86E12C872A4D4E20,0x9969A28BCE3E087A,0xFAFB2EB79D9C4B55, + 0x056A4156B6D92CB2,0x5A3AE6A5DEBEA296,0x22A3B026A8292580,0x53C85B3B36AD1581, + 0xB11E900117B87583,0xC51F3A4A3FE56930,0xE019E1EDCF3621BD,0xEC811D2591FCBA18, + 0x445B7D4C4D524A1D,0xA8DA6069DCAEF005,0x58F5CC72309DE329,0xD4C062596B7FF570, + 0xCE22AD0339D59F98,0x591CD99747024DF8,0x8B90C5AA03187B54,0xF663D27FC356D0F0, + 0xD8589E9135B56ED5,0x35309651D3D67A1C,0x12F96721CD26732E,0xD28C1C3D441A36AC, + 0x492A946164077F69,0x2D1D73DC6F5F514B,0x6F0A70F40D68D88A,0x60B4B30ECA1EAC41, + 0xD36509D83385987D,0x0B3D97490630F6A8,0x9ECCC90A96C46577,0xA20EE2C5AD01A87C, + 0xE49AB55E0E70A3DE,0xA4429CA182646BA0,0xDA97B446DB962F6A,0xCCED87D4D7F6DE27, + 0x2AB8185D37A53C46,0x9F25DCEFE15BCBA6,0xC19C6EF9FEA3EB53,0xA764A3931BD884CE, + 0x2FD2590B817C10F4,0x56A21A6D80743933,0xE573A0BB79EF0D0F,0x155C0CA095DC1E23, + 0x6C2C4FC694D437E4,0x10364DF623053291,0xDD32DFC7836C4267,0x03263F3299BCEF6E, + 0x66F8CD6AE57B6F9D,0x8C35AE2B5BE21659,0x31B3C2E21290F87F,0x93BD2027BF915003, + 0x69460E90220D1B56,0x299E276FAE19D328,0x63928C3C53A2432F,0x7082FEF8E91B9ED0, + 0xBC6F792C3EED40F7,0x4C40D537D2DE53DB,0x75E8BFAE5FC2B262,0x4DA9C0D2A541FD0A, + 0x4E8FFFE03CFD1264,0x2620E495696FA7E3,0xE1F0F408B8A98F6C,0xD1AA230FDDA6D9C2, + 0xC7D0109DD1C6288F,0x8A79D04F7487D585,0x4694579BA3710BA2,0x38417F7CFA834F68, + 0x1D47A4DB0A5007E5,0x206C9AF1460A643F,0xA128DDF734BD4712,0x8144470672B7232D, + 0xF2E086CC02105293,0x182DE58DBC892B57,0xCAA1F9B0F8931DFB,0x6B892447CC2E5AE9, + 0xF9DD11850420A43B,0x4BE5BEB68A243ED6,0x5584255F19C8D65D,0x3B67404E633FA006, + 0xA68DB6766C472A1F,0xF78AC79AB4C97E21,0xC353442E1080AAEC,0x9A4F9DB95782E714 +},{ + 0x05BA7BC82C9B3220,0x31A54665F8B65E4F,0xB1B651F77547F4D4,0x8BFA0D857BA46682, + 0x85A96C5AA16A98BB,0x990FAEF908EB79C9,0xA15E37A247F4A62D,0x76857DCD5D27741E, + 0xF8C50B800A1820BC,0xBE65DCB201F7A2B4,0x666D1B986F9426E7,0x4CC921BF53C4E648, + 0x95410A0F93D9CA42,0x20CDCCAA647BA4EF,0x429A4060890A1871,0x0C4EA4F69B32B38B, + 0xCCDA362DDE354CD3,0x96DC23BC7C5B2FA9,0xC309BB68AA851AB3,0xD26131A73648E013, + 0x021DC52941FC4DB2,0xCD5ADAB7704BE48A,0xA77965D984ED71E6,0x32386FD61734BBA4, + 0xE82D6DD538AB7245,0x5C2147EA6177B4B1,0x5DA1AB70CF091CE8,0xAC907FCE72B8BDFF, + 0x57C85DFD972278A8,0xA4E44C6A6B6F940D,0x3851995B4F1FDFE4,0x62578CCAED71BC9E, + 0xD9882BB0C01D2C0A,0x917B9D5D113C503B,0xA2C31E11A87643C6,0xE463C923A399C1CE, + 0xF71686C57EA876DC,0x87B4A973E096D509,0xAF0D567D9D3A5814,0xB40C2A3F59DCC6F4, + 0x3602F88495D121DD,0xD3E1DD3D9836484A,0xF945E71AA46688E5,0x7518547EB2A591F5, + 0x9366587450C01D89,0x9EA81018658C065B,0x4F54080CBC4603A3,0x2D0384C65137BF3D, + 0xDC325078EC861E2A,0xEA30A8FC79573FF7,0x214D2030CA050CB6,0x65F0322B8016C30C, + 0x69BE96DD1B247087,0xDB95EE9981E161B8,0xD1FC1814D9CA05F8,0x820ED2BBCC0DE729, + 0x63D76050430F14C7,0x3BCCB0E8A09D3A0F,0x8E40764D573F54A2,0x39D175C1E16177BD, + 0x12F5A37C734F1F4B,0xAB37C12F1FDFC26D,0x5648B167395CD0F1,0x6C04ED1537BF42A7, + 0xED97161D14304065,0x7D6C67DAAB72B807,0xEC17FA87BA4EE83C,0xDFAF79CB0304FBC1, + 0x733F060571BC463E,0x78D61C1287E98A27,0xD07CF48E77B4ADA1,0xB9C262536C90DD26, + 0xE2449B5860801605,0x8FC09AD7F941FCFB,0xFAD8CEA94BE46D0E,0xA343F28B0608EB9F, + 0x9B126BD04917347B,0x9A92874AE7699C22,0x1B017C42C4E69EE0,0x3A4C5C720EE39256, + 0x4B6E9F5E3EA399DA,0x6BA353F45AD83D35,0xE7FEE0904C1B2425,0x22D009832587E95D, + 0x842980C00F1430E2,0xC6B3C0A0861E2893,0x087433A419D729F2,0x341F3DADD42D6C6F, + 0xEE0A3FAEFBB2A58E,0x4AEE73C490DD3183,0xAAB72DB5B1A16A34,0xA92A04065E238FDF, + 0x7B4B35A1686B6FCC,0x6A23BF6EF4A6956C,0x191CB96B851AD352,0x55D598D4D6DE351A, + 0xC9604DE5F2AE7EF3,0x1CA6C2A3A981E172,0xDE2F9551AD7A5398,0x3025AAFF56C8F616, + 0x15521D9D1E2860D9,0x506FE31CFA45073A,0x189C55F12B647B0B,0x0180EC9AAE7EA859, + 0x7CEC8B40050C105E,0x2350E5198BF94104,0xEF8AD33455CC0DD7,0x07A7BEE16D677F92, + 0xE5E325B90DE76997,0x5A061591A26E637A,0xB611EF1618208B46,0x09F4DF3EB7A981AB, + 0x1EBB078AE87DACC0,0xB791038CB65E231F,0x0FD38D4574B05660,0x67EDF702C1EA8EBE, + 0xBA5F4BE0831238CD,0xE3C477C2CEFEBE5C,0x0DCE486C354C1BD2,0x8C5DB36416C31910, + 0x26EA9ED1A7627324,0x039D29B3EF82E5EB,0x9F28FC82CBF2AE02,0xA8AAE89CF05D2786, + 0x431AACFA2774B028,0xCF471F9E31B7A938,0x581BD0B8E3922EC8,0xBC78199B400BEF06, + 0x90FB71C7BF42F862,0x1F3BEB1046030499,0x683E7A47B55AD8DE,0x988F4263A695D190, + 0xD808C72A6E638453,0x0627527BC319D7CB,0xEBB04466D72997AE,0xE67E0C0AE2658C7C, + 0x14D2F107B056C880,0x7122C32C30400B8C,0x8A7AE11FD5DACEDB,0xA0DEDB38E98A0E74, + 0xAD109354DCC615A6,0x0BE91A17F655CC19,0x8DDD5FFEB8BDB149,0xBFE53028AF890AED, + 0xD65BA6F5B4AD7A6A,0x7956F0882997227E,0x10E8665532B352F9,0x0E5361DFDACEFE39, + 0xCEC7F3049FC90161,0xFF62B561677F5F2E,0x975CCF26D22587F0,0x51EF0F86543BAF63, + 0x2F1E41EF10CBF28F,0x52722635BBB94A88,0xAE8DBAE73344F04D,0x410769D36688FD9A, + 0xB3AB94DE34BBB966,0x801317928DF1AA9B,0xA564A0F0C5113C54,0xF131D4BEBDB1A117, + 0x7F71A2F3EA8EF5B5,0x40878549C8F655C3,0x7EF14E6944F05DEC,0xD44663DCF55137D8, + 0xF2ACFD0D523344FC,0x0000000000000000,0x5FBC6E598EF5515A,0x16CF342EF1AA8532, + 0xB036BD6DDB395C8D,0x13754FE6DD31B712,0xBBDFA77A2D6C9094,0x89E7C8AC3A582B30, + 0x3C6B0E09CDFA459D,0xC4AE0589C7E26521,0x49735A777F5FD468,0xCAFD64561D2C9B18, + 0xDA1502032F9FC9E1,0x8867243694268369,0x3782141E3BAF8984,0x9CB5D53124704BE9, + 0xD7DB4A6F1AD3D233,0xA6F989432A93D9BF,0x9D3539AB8A0EE3B0,0x53F2CAAF15C7E2D1, + 0x6E19283C76430F15,0x3DEBE2936384EDC4,0x5E3C82C3208BF903,0x33B8834CB94A13FD, + 0x6470DEB12E686B55,0x359FD1377A53C436,0x61CAA57902F35975,0x043A975282E59A79, + 0xFD7F70482683129C,0xC52EE913699CCD78,0x28B9FF0E7DAC8D1D,0x5455744E78A09D43, + 0xCB7D88CCB3523341,0x44BD121B4A13CFBA,0x4D49CD25FDBA4E11,0x3E76CB208C06082F, + 0x3FF627BA2278A076,0xC28957F204FBB2EA,0x453DFE81E46D67E3,0x94C1E6953DA7621B, + 0x2C83685CFF491764,0xF32C1197FC4DECA5,0x2B24D6BD922E68F6,0xB22B78449AC5113F, + 0x48F3B6EDD1217C31,0x2E9EAD75BEB55AD6,0x174FD8B45FD42D6B,0x4ED4E4961238ABFA, + 0x92E6B4EEFEBEB5D0,0x46A0D7320BEF8208,0x47203BA8A5912A51,0x24F75BF8E69E3E96, + 0xF0B1382413CF094E,0xFEE259FBC901F777,0x276A724B091CDB7D,0xBDF8F501EE75475F, + 0x599B3C224DEC8691,0x6D84018F99C1EAFE,0x7498B8E41CDB39AC,0xE0595E71217C5BB7, + 0x2AA43A273C50C0AF,0xF50B43EC3F543B6E,0x838E3E2162734F70,0xC09492DB4507FF58, + 0x72BFEA9FDFC2EE67,0x11688ACF9CCDFAA0,0x1A8190D86A9836B9,0x7ACBD93BC615C795, + 0xC7332C3A286080CA,0x863445E94EE87D50,0xF6966A5FD0D6DE85,0xE9AD814F96D5DA1C, + 0x70A22FB69E3EA3D5,0x0A69F68D582B6440,0xB8428EC9C2EE757F,0x604A49E3AC8DF12C, + 0x5B86F90B0C10CB23,0xE1D9B2EB8F02F3EE,0x29391394D3D22544,0xC8E0A17F5CD0D6AA, + 0xB58CC6A5F7A26EAD,0x8193FB08238F02C2,0xD5C68F465B2F9F81,0xFCFF9CD288FDBAC5, + 0x77059157F359DC47,0x1D262E3907FF492B,0xFB582233E59AC557,0xDDB2BCE242F8B673, + 0x2577B76248E096CF,0x6F99C4A6D83DA74C,0xC1147E41EB795701,0xF48BAF76912A9337 +},{ + 0x3EF29D249B2C0A19,0xE9E16322B6F8622F,0x5536994047757F7A,0x9F4D56D5A47B0B33, + 0x822567466AA1174C,0xB8F5057DEB082FB2,0xCC48C10BF4475F53,0x373088D4275DEC3A, + 0x968F4325180AED10,0x173D232CF7016151,0xAE4ED09F946FCC13,0xFD4B4741C4539873, + 0x1B5B3F0DD9933765,0x2FFCB0967B644052,0xE02376D20A89840C,0xA3AE3A70329B18D7, + 0x419CBD2335DE8526,0xFAFEBF115B7C3199,0x0397074F85AA9B0D,0xC58AD4FB4836B970, + 0xBEC60BE3FC4104A8,0x1EFF36DC4B708772,0x131FDC33ED8453B6,0x0844E33E341764D3, + 0x0FF11B6EAB38CD39,0x64351F0A7761B85A,0x3B5694F509CFBA0E,0x30857084B87245D0, + 0x47AFB3BD2297AE3C,0xF2BA5C2F6F6B554A,0x74BDC4761F4F70E1,0xCFDFC64471EDC45E, + 0xE610784C1DC0AF16,0x7ACA29D63C113F28,0x2DED411776A859AF,0xAC5F211E99A3D5EE, + 0xD484F949A87EF33B,0x3CE36CA596E013E4,0xD120F0983A9D432C,0x6BC40464DC597563, + 0x69D5F5E5D1956C9E,0x9AE95F043698BB24,0xC9ECC8DA66A4EF44,0xD69508C8A5B2EAC6, + 0xC40C2235C0503B80,0x38C193BA8C652103,0x1CEEC75D46BC9E8F,0xD331011937515AD1, + 0xD8E2E56886ECA50F,0xB137108D5779C991,0x709F3B6905CA4206,0x4FEB50831680CAEF, + 0xEC456AF3241BD238,0x58D673AFE181ABBE,0x242F54E7CAD9BF8C,0x0211F1810DCC19FD, + 0x90BC4DBB0F43C60A,0x9518446A9DA0761D,0xA1BFCBF13F57012A,0x2BDE4F8961E172B5, + 0x27B853A84F732481,0xB0B1E643DF1F4B61,0x18CC38425C39AC68,0xD2B7F7D7BF37D821, + 0x3103864A3014C720,0x14AA246372ABFA5C,0x6E600DB54EBAC574,0x394765740403A3F3, + 0x09C215F0BC71E623,0x2A58B947E987F045,0x7B4CDF18B477BDD8,0x9709B5EB906C6FE0, + 0x73083C268060D90B,0xFEDC400E41F9037E,0x284948C6E44BE9B8,0x728ECAE808065BFB, + 0x06330E9E17492B1A,0x5950856169E7294E,0xBAE4F4FCE6C4364F,0xCA7BCF95E30E7449, + 0x7D7FD186A33E96C2,0x52836110D85AD690,0x4DFAA1021B4CD312,0x913ABB75872544FA, + 0xDD46ECB9140F1518,0x3D659A6B1E869114,0xC23F2CABD719109A,0xD713FE062DD46836, + 0xD0A60656B2FBC1DC,0x221C5A79DD909496,0xEFD26DBCA1B14935,0x0E77EDA0235E4FC9, + 0xCBFD395B6B68F6B9,0x0DE0EAEFA6F4D4C4,0x0422FF1F1A8532E7,0xF969B85EDED6AA94, + 0x7F6E2007AEF28F3F,0x3AD0623B81A938FE,0x6624EE8B7AADA1A7,0xB682E8DDC856607B, + 0xA78CC56F281E2A30,0xC79B257A45FAA08D,0x5B4174E0642B30B3,0x5F638BFF7EAE0254, + 0x4BC9AF9C0C05F808,0xCE59308AF98B46AE,0x8FC58DA9CC55C388,0x803496C7676D0EB1, + 0xF33CAAE1E70DD7BA,0xBB6202326EA2B4BF,0xD5020F87201871CB,0x9D5CA754A9B712CE, + 0x841669D87DE83C56,0x8A6184785EB6739F,0x420BBA6CB0741E2B,0xF12D5B60EAC1CE47, + 0x76AC35F71283691C,0x2C6BB7D9FECEDB5F,0xFCCDB18F4C351A83,0x1F79C012C3160582, + 0xF0ABADAE62A74CB7,0xE1A5801C82EF06FC,0x67A21845F2CB2357,0x5114665F5DF04D9D, + 0xBF40FD2D74278658,0xA0393D3FB73183DA,0x05A409D192E3B017,0xA9FB28CF0B4065F9, + 0x25A9A22942BF3D7C,0xDB75E22703463E02,0xB326E10C5AB5D06C,0xE7968E8295A62DE6, + 0xB973F3B3636EAD42,0xDF571D3819C30CE5,0xEE549B7229D7CBC5,0x12992AFD65E2D146, + 0xF8EF4E9056B02864,0xB7041E134030E28B,0xC02EDD2ADAD50967,0x932B4AF48AE95D07, + 0x6FE6FB7BC6DC4784,0x239AACB755F61666,0x401A4BEDBDB807D6,0x485EA8D389AF6305, + 0xA41BC220ADB4B13D,0x753B32B89729F211,0x997E584BB3322029,0x1D683193CEDA1C7F, + 0xFF5AB6C0C99F818E,0x16BBD5E27F67E3A1,0xA59D34EE25D233CD,0x98F8AE853B54A2D9, + 0x6DF70AFACB105E79,0x795D2E99B9BBA425,0x8E437B6744334178,0x0186F6CE886682F0, + 0xEBF092A3BB347BD2,0xBCD7FA62F18D1D55,0xADD9D7D011C5571E,0x0BD3E471B1BDFFDE, + 0xAA6C2F808EEAFEF4,0x5EE57D31F6C880A4,0xF50FA47FF044FCA0,0x1ADDC9C351F5B595, + 0xEA76646D3352F922,0x0000000000000000,0x85909F16F58EBEA6,0x46294573AAF12CCC, + 0x0A5512BF39DB7D2E,0x78DBD85731DD26D5,0x29CFBE086C2D6B48,0x218B5D36583A0F9B, + 0x152CD2ADFACD78AC,0x83A39188E2C795BC,0xC3B9DA655F7F926A,0x9ECBA01B2C1D89C3, + 0x07B5F8509F2FA9EA,0x7EE8D6C926940DCF,0x36B67E1AAF3B6ECA,0x86079859702425AB, + 0xFB7849DFD31AB369,0x4C7C57CC932A51E2,0xD96413A60E8A27FF,0x263EA566C715A671, + 0x6C71FC344376DC89,0x4A4F595284637AF8,0xDAF314E98B20BCF2,0x572768C14AB96687, + 0x1088DB7C682EC8BB,0x887075F9537A6A62,0x2E7A4658F302C2A2,0x619116DBE582084D, + 0xA87DDE018326E709,0xDCC01A779C6997E8,0xEDC39C3DAC7D50C8,0xA60A33A1A078A8C0, + 0xC1A82BE452B38B97,0x3F746BEA134A88E9,0xA228CCBEBAFD9A27,0xABEAD94E068C7C04, + 0xF48952B178227E50,0x5CF48CB0FB049959,0x6017E0156DE48ABD,0x4438B4F2A73D3531, + 0x8C528AE649FF5885,0xB515EF924DFCFB76,0x0C661C212E925634,0xB493195CC59A7986, + 0x9CDA519A21D1903E,0x32948105B5BE5C2D,0x194ACE8CD45F2E98,0x438D4CA238129CDB, + 0x9B6FA9CABEFE39D4,0x81B26009EF0B8C41,0xDED1EBF691A58E15,0x4E6DA64D9EE6481F, + 0x54B06F8ECF13FD8A,0x49D85E1D01C9E1F5,0xAFC826511C094EE3,0xF698A33075EE67AD, + 0x5AC7822EEC4DB243,0x8DD47C28C199DA75,0x89F68337DB1CE892,0xCDCE37C57C21DDA3, + 0x530597DE503C5460,0x6A42F2AA543FF793,0x5D727A7E73621BA9,0xE232875307459DF1, + 0x56A19E0FC2DFE477,0xC61DD3B4CD9C227D,0xE5877F03986A341B,0x949EB2A415C6F4ED, + 0x6206119460289340,0x6380E75AE84E11B0,0x8BE772B6D6D0F16F,0x50929091D596CF6D, + 0xE86795EC3E9EE0DF,0x7CF927482B581432,0xC86A3E14EEC26DB4,0x7119CDA78DACC0F6, + 0xE40189CD100CB6EB,0x92ADBC3A028FDFF7,0xB2A017C2D2D3529C,0x200DABF8D05C8D6B, + 0x34A78F9BA2F77737,0xE3B4719D8F231F01,0x45BE423C2F5BB7C1,0xF71E55FEFD88E55D, + 0x6853032B59F3EE6E,0x65B3E9C4FF073AAA,0x772AC3399AE5EBEC,0x87816E97F842A75B, + 0x110E2DB2E0484A4B,0x331277CB3DD8DEDD,0xBD510CAC79EB9FA5,0x352179552A91F5C7 +},{ + 0x8AB0A96846E06A6D,0x43C7E80B4BF0B33A,0x08C9B3546B161EE5,0x39F1C235EBA990BE, + 0xC1BEF2376606C7B2,0x2C209233614569AA,0xEB01523B6FC3289A,0x946953AB935ACEDD, + 0x272838F63E13340E,0x8B0455ECA12BA052,0x77A1B2C4978FF8A2,0xA55122CA13E54086, + 0x2276135862D3F1CD,0xDB8DDFDE08B76CFE,0x5D1E12C89E4A178A,0x0E56816B03969867, + 0xEE5F79953303ED59,0xAFED748BAB78D71D,0x6D929F2DF93E53EE,0xF5D8A8F8BA798C2A, + 0xF619B1698E39CF6B,0x95DDAF2F749104E2,0xEC2A9C80E0886427,0xCE5C8FD8825B95EA, + 0xC4E0D9993AC60271,0x4699C3A5173076F9,0x3D1B151F50A29F42,0x9ED505EA2BC75946, + 0x34665ACFDC7F4B98,0x61B1FB53292342F7,0xC721C0080E864130,0x8693CD1696FD7B74, + 0x872731927136B14B,0xD3446C8A63A1721B,0x669A35E8A6680E4A,0xCAB658F239509A16, + 0xA4E5DE4EF42E8AB9,0x37A7435EE83F08D9,0x134E6239E26C7F96,0x82791A3C2DF67488, + 0x3F6EF00A8329163C,0x8E5A7E42FDEB6591,0x5CAAEE4C7981DDB5,0x19F234785AF1E80D, + 0x255DDDE3ED98BD70,0x50898A32A99CCCAC,0x28CA4519DA4E6656,0xAE59880F4CB31D22, + 0x0D9798FA37D6DB26,0x32F968F0B4FFCD1A,0xA00F09644F258545,0xFA3AD5175E24DE72, + 0xF46C547C5DB24615,0x713E80FBFF0F7E20,0x7843CF2B73D2AAFA,0xBD17EA36AEDF62B4, + 0xFD111BACD16F92CF,0x4ABAA7DBC72D67E0,0xB3416B5DAD49FAD3,0xBCA316B24914A88B, + 0x15D150068AECF914,0xE27C1DEBE31EFC40,0x4FE48C759BEDA223,0x7EDCFD141B522C78, + 0x4E5070F17C26681C,0xE696CAC15815F3BC,0x35D2A64B3BB481A7,0x800CFF29FE7DFDF6, + 0x1ED9FAC3D5BAA4B0,0x6C2663A91EF599D1,0x03C1199134404341,0xF7AD4DED69F20554, + 0xCD9D9649B61BD6AB,0xC8C3BDE7EADB1368,0xD131899FB02AFB65,0x1D18E352E1FAE7F1, + 0xDA39235AEF7CA6C1,0xA1BBF5E0A8EE4F7A,0x91377805CF9A0B1E,0x3138716180BF8E5B, + 0xD9F83ACBDB3CE580,0x0275E515D38B897E,0x472D3F21F0FBBCC6,0x2D946EB7868EA395, + 0xBA3C248D21942E09,0xE7223645BFDE3983,0xFF64FEB902E41BB1,0xC97741630D10D957, + 0xC3CB1722B58D4ECC,0xA27AEC719CAE0C3B,0x99FECB51A48C15FB,0x1465AC826D27332B, + 0xE1BD047AD75EBF01,0x79F733AF941960C5,0x672EC96C41A3C475,0xC27FEBA6524684F3, + 0x64EFD0FD75E38734,0xED9E60040743AE18,0xFB8E2993B9EF144D,0x38453EB10C625A81, + 0x6978480742355C12,0x48CF42CE14A6EE9E,0x1CAC1FD606312DCE,0x7B82D6BA4792E9BB, + 0x9D141C7B1F871A07,0x5616B80DC11C4A2E,0xB849C198F21FA777,0x7CA91801C8D9A506, + 0xB1348E487EC273AD,0x41B20D1E987B3A44,0x7460AB55A3CFBBE3,0x84E628034576F20A, + 0x1B87D16D897A6173,0x0FE27DEFE45D5258,0x83CDE6B8CA3DBEB7,0x0C23647ED01D1119, + 0x7A362A3EA0592384,0xB61F40F3F1893F10,0x75D457D1440471DC,0x4558DA34237035B8, + 0xDCA6116587FC2043,0x8D9B67D3C9AB26D0,0x2B0B5C88EE0E2517,0x6FE77A382AB5DA90, + 0x269CC472D9D8FE31,0x63C41E46FAA8CB89,0xB7ABBC771642F52F,0x7D1DE4852F126F39, + 0xA8C6BA3024339BA0,0x600507D7CEE888C8,0x8FEE82C61A20AFAE,0x57A2448926D78011, + 0xFCA5E72836A458F0,0x072BCEBB8F4B4CBD,0x497BBE4AF36D24A1,0x3CAFE99BB769557D, + 0x12FA9EBD05A7B5A9,0xE8C04BAA5B836BDB,0x4273148FAC3B7905,0x908384812851C121, + 0xE557D3506C55B0FD,0x72FF996ACB4F3D61,0x3EDA0C8E64E2DC03,0xF0868356E6B949E9, + 0x04EAD72ABB0B0FFC,0x17A4B5135967706A,0xE3C8E16F04D5367F,0xF84F30028DAF570C, + 0x1846C8FCBD3A2232,0x5B8120F7F6CA9108,0xD46FA231ECEA3EA6,0x334D947453340725, + 0x58403966C28AD249,0xBED6F3A79A9F21F5,0x68CCB483A5FE962D,0xD085751B57E1315A, + 0xFED0023DE52FD18E,0x4B0E5B5F20E6ADDF,0x1A332DE96EB1AB4C,0xA3CE10F57B65C604, + 0x108F7BA8D62C3CD7,0xAB07A3A11073D8E1,0x6B0DAD1291BED56C,0xF2F366433532C097, + 0x2E557726B2CEE0D4,0x0000000000000000,0xCB02A476DE9B5029,0xE4E32FD48B9E7AC2, + 0x734B65EE2C84F75E,0x6E5386BCCD7E10AF,0x01B4FC84E7CBCA3F,0xCFE8735C65905FD5, + 0x3613BFDA0FF4C2E6,0x113B872C31E7F6E8,0x2FE18BA255052AEB,0xE974B72EBC48A1E4, + 0x0ABC5641B89D979B,0xB46AA5E62202B66E,0x44EC26B0C4BBFF87,0xA6903B5B27A503C7, + 0x7F680190FC99E647,0x97A84A3AA71A8D9C,0xDD12EDE16037EA7C,0xC554251DDD0DC84E, + 0x88C54C7D956BE313,0x4D91696048662B5D,0xB08072CC9909B992,0xB5DE5962C5C97C51, + 0x81B803AD19B637C9,0xB2F597D94A8230EC,0x0B08AAC55F565DA4,0xF1327FD2017283D6, + 0xAD98919E78F35E63,0x6AB9519676751F53,0x24E921670A53774F,0xB9FD3D1C15D46D48, + 0x92F66194FBDA485F,0x5A35DC7311015B37,0xDED3F4705477A93D,0xC00A0EB381CD0D8D, + 0xBB88D809C65FE436,0x16104997BEACBA55,0x21B70AC95693B28C,0x59F4C5E225411876, + 0xD5DB5EB50B21F499,0x55D7A19CF55C096F,0xA97246B4C3F8519F,0x8552D487A2BD3835, + 0x54635D181297C350,0x23C2EFDC85183BF2,0x9F61F96ECC0C9379,0x534893A39DDC8FED, + 0x5EDF0B59AA0A54CB,0xAC2C6D1A9F38945C,0xD7AEBBA0D8AA7DE7,0x2ABFA00C09C5EF28, + 0xD84CC64F3CF72FBF,0x2003F64DB15878B3,0xA724C7DFC06EC9F8,0x069F323F68808682, + 0xCC296ACD51D01C94,0x055E2BAE5CC0C5C3,0x6270E2C21D6301B6,0x3B842720382219C0, + 0xD2F0900E846AB824,0x52FC6F277A1745D2,0xC6953C8CE94D8B0F,0xE009F8FE3095753E, + 0x655B2C7992284D0B,0x984A37D54347DFC4,0xEAB5AEBF8808E2A5,0x9A3FD2C090CC56BA, + 0x9CA0E0FFF84CD038,0x4C2595E4AFADE162,0xDF6708F4B3BC6302,0xBF620F237D54EBCA, + 0x93429D101C118260,0x097D4FD08CDDD4DA,0x8C2F9B572E60ECEF,0x708A7C7F18C4B41F, + 0x3A30DBA4DFE9D3FF,0x4006F19A7FB0F07B,0x5F6BF7DD4DC19EF4,0x1F6D064732716E8F, + 0xF9FBCC866A649D33,0x308C8DE567744464,0x8971B0F972A0292C,0xD61A47243F61B7D8, + 0xEFEB8511D4C82766,0x961CB6BE40D147A3,0xAAB35F25F7B812DE,0x76154E407044329D, + 0x513D76B64E570693,0xF3479AC7D2F90AA8,0x9B8B2E4477079C85,0x297EB99D3D85AC69 +},{ + 0x7E37E62DFC7D40C3,0x776F25A4EE939E5B,0xE045C850DD8FB5AD,0x86ED5BA711FF1952, + 0xE91D0BD9CF616B35,0x37E0AB256E408FFB,0x9607F6C031025A7A,0x0B02F5E116D23C9D, + 0xF3D8486BFB50650C,0x621CFF27C40875F5,0x7D40CB71FA5FD34A,0x6DAA6616DAA29062, + 0x9F5F354923EC84E2,0xEC847C3DC507C3B3,0x025A3668043CE205,0xA8BF9E6C4DAC0B19, + 0xFA808BE2E9BEBB94,0xB5B99C5277C74FA3,0x78D9BC95F0397BCC,0xE332E50CDBAD2624, + 0xC74FCE129332797E,0x1729ECEB2EA709AB,0xC2D6B9F69954D1F8,0x5D898CBFBAB8551A, + 0x859A76FB17DD8ADB,0x1BE85886362F7FB5,0xF6413F8FF136CD8A,0xD3110FA5BBB7E35C, + 0x0A2FEED514CC4D11,0xE83010EDCD7F1AB9,0xA1E75DE55F42D581,0xEEDE4A55C13B21B6, + 0xF2F5535FF94E1480,0x0CC1B46D1888761E,0xBCE15FDB6529913B,0x2D25E8975A7181C2, + 0x71817F1CE2D7A554,0x2E52C5CB5C53124B,0xF9F7A6BEEF9C281D,0x9E722E7D21F2F56E, + 0xCE170D9B81DCA7E6,0x0E9B82051CB4941B,0x1E712F623C49D733,0x21E45CFA42F9F7DC, + 0xCB8E7A7F8BBA0F60,0x8E98831A010FB646,0x474CCF0D8E895B23,0xA99285584FB27A95, + 0x8CC2B57205335443,0x42D5B8E984EFF3A5,0x012D1B34021E718C,0x57A6626AAE74180B, + 0xFF19FC06E3D81312,0x35BA9D4D6A7C6DFE,0xC9D44C178F86ED65,0x506523E6A02E5288, + 0x03772D5C06229389,0x8B01F4FE0B691EC0,0xF8DABD8AED825991,0x4C4E3AEC985B67BE, + 0xB10DF0827FBF96A9,0x6A69279AD4F8DAE1,0xE78689DCD3D5FF2E,0x812E1A2B1FA553D1, + 0xFBAD90D6EBA0CA18,0x1AC543B234310E39,0x1604F7DF2CB97827,0xA6241C6951189F02, + 0x753513CCEAAF7C5E,0x64F2A59FC84C4EFA,0x247D2B1E489F5F5A,0xDB64D718AB474C48, + 0x79F4A7A1F2270A40,0x1573DA832A9BEBAE,0x3497867968621C72,0x514838D2A2302304, + 0xF0AF6537FD72F685,0x1D06023E3A6B44BA,0x678588C3CE6EDD73,0x66A893F7CC70ACFF, + 0xD4D24E29B5EDA9DF,0x3856321470EA6A6C,0x07C3418C0E5A4A83,0x2BCBB22F5635BACD, + 0x04B46CD00878D90A,0x06EE5AB80C443B0F,0x3B211F4876C8F9E5,0x0958C38912EEDE98, + 0xD14B39CDBF8B0159,0x397B292072F41BE0,0x87C0409313E168DE,0xAD26E98847CAA39F, + 0x4E140C849C6785BB,0xD5FF551DB7F3D853,0xA0CA46D15D5CA40D,0xCD6020C787FE346F, + 0x84B76DCF15C3FB57,0xDEFDA0FCA121E4CE,0x4B8D7B6096012D3D,0x9AC642AD298A2C64, + 0x0875D8BD10F0AF14,0xB357C6EA7B8374AC,0x4D6321D89A451632,0xEDA96709C719B23F, + 0xF76C24BBF328BC06,0xC662D526912C08F2,0x3CE25EC47892B366,0xB978283F6F4F39BD, + 0xC08C8F9E9D6833FD,0x4F3917B09E79F437,0x593DE06FB2C08C10,0xD6887841B1D14BDA, + 0x19B26EEE32139DB0,0xB494876675D93E2F,0x825937771987C058,0x90E9AC783D466175, + 0xF1827E03FF6C8709,0x945DC0A8353EB87F,0x4516F9658AB5B926,0x3F9573987EB020EF, + 0xB855330B6D514831,0x2AE6A91B542BCB41,0x6331E413C6160479,0x408F8E8180D311A0, + 0xEFF35161C325503A,0xD06622F9BD9570D5,0x8876D9A20D4B8D49,0xA5533135573A0C8B, + 0xE168D364DF91C421,0xF41B09E7F50A2F8F,0x12B09B0F24C1A12D,0xDA49CC2CA9593DC4, + 0x1F5C34563E57A6BF,0x54D14F36A8568B82,0xAF7CDFE043F6419A,0xEA6A2685C943F8BC, + 0xE5DCBFB4D7E91D2B,0xB27ADDDE799D0520,0x6B443CAED6E6AB6D,0x7BAE91C9F61BE845, + 0x3EB868AC7CAE5163,0x11C7B65322E332A4,0xD23C1491B9A992D0,0x8FB5982E0311C7CA, + 0x70AC6428E0C9D4D8,0x895BC2960F55FCC5,0x76423E90EC8DEFD7,0x6FF0507EDE9E7267, + 0x3DCF45F07A8CC2EA,0x4AA06054941F5CB1,0x5810FB5BB0DEFD9C,0x5EFEA1E3BC9AC693, + 0x6EDD4B4ADC8003EB,0x741808F8E8B10DD2,0x145EC1B728859A22,0x28BC9F7350172944, + 0x270A06424EBDCCD3,0x972AEDF4331C2BF6,0x059977E40A66A886,0x2550302A4A812ED6, + 0xDD8A8DA0A7037747,0xC515F87A970E9B7B,0x3023EAA9601AC578,0xB7E3AA3A73FBADA6, + 0x0FB699311EAAE597,0x0000000000000000,0x310EF19D6204B4F4,0x229371A644DB6455, + 0x0DECAF591A960792,0x5CA4978BB8A62496,0x1C2B190A38753536,0x41A295B582CD602C, + 0x3279DCC16426277D,0xC1A194AA9F764271,0x139D803B26DFD0A1,0xAE51C4D441E83016, + 0xD813FA44AD65DFC1,0xAC0BF2BC45D4D213,0x23BE6A9246C515D9,0x49D74D08923DCF38, + 0x9D05032127D066E7,0x2F7FDEFF5E4D63C7,0xA47E2A0155247D07,0x99B16FF12FA8BFED, + 0x4661D4398C972AAF,0xDFD0BBC8A33F9542,0xDCA79694A51D06CB,0xB020EBB67DA1E725, + 0xBA0F0563696DAA34,0xE4F1A480D5F76CA7,0xC438E34E9510EAF7,0x939E81243B64F2FC, + 0x8DEFAE46072D25CF,0x2C08F3A3586FF04E,0xD7A56375B3CF3A56,0x20C947CE40E78650, + 0x43F8A3DD86F18229,0x568B795EAC6A6987,0x8003011F1DBB225D,0xF53612D3F7145E03, + 0x189F75DA300DEC3C,0x9570DB9C3720C9F3,0xBB221E576B73DBB8,0x72F65240E4F536DD, + 0x443BE25188ABC8AA,0xE21FFE38D9B357A8,0xFD43CA6EE7E4F117,0xCAA3614B89A47EEC, + 0xFE34E732E1C6629E,0x83742C431B99B1D4,0xCF3A16AF83C2D66A,0xAAE5A8044990E91C, + 0x26271D764CA3BD5F,0x91C4B74C3F5810F9,0x7C6DD045F841A2C6,0x7F1AFD19FE63314F, + 0xC8F957238D989CE9,0xA709075D5306EE8E,0x55FC5402AA48FA0E,0x48FA563C9023BEB4, + 0x65DFBEABCA523F76,0x6C877D22D8BCE1EE,0xCC4D3BF385E045E3,0xBEBB69B36115733E, + 0x10EAAD6720FD4328,0xB6CEB10E71E5DC2A,0xBDCC44EF6737E0B7,0x523F158EA412B08D, + 0x989C74C52DB6CE61,0x9BEB59992B945DE8,0x8A2CEFCA09776F4C,0xA3BD6B8D5B7E3784, + 0xEB473DB1CB5D8930,0xC3FBA2C29B4AA074,0x9C28181525CE176B,0x683311F2D0C438E4, + 0x5FD3BAD7BE84B71F,0xFC6ED15AE5FA809B,0x36CDB0116C5EFE77,0x29918447520958C8, + 0xA29070B959604608,0x53120EBAA60CC101,0x3A0C047C74D68869,0x691E0AC6D2DA4968, + 0x73DB4974E6EB4751,0x7A838AFDF40599C9,0x5A4ACD33B4E21F99,0x6046C94FC03497F0, + 0xE6AB92E8D1CB8EA2,0x3354C7F5663856F1,0xD93EE170AF7BAE4D,0x616BD27BC22AE67C, + 0x92B39A10397A8370,0xABC8B3304B8E9890,0xBF967287630B02B2,0x5B67D607B6FC6E15 +},{ + 0xD031C397CE553FE6,0x16BA5B01B006B525,0xA89BADE6296E70C8,0x6A1F525D77D3435B, + 0x6E103570573DFA0B,0x660EFB2A17FC95AB,0x76327A9E97634BF6,0x4BAD9D6462458BF5, + 0xF1830CAEDBC3F748,0xC5C8F542669131FF,0x95044A1CDC48B0CB,0x892962DF3CF8B866, + 0xB0B9E208E930C135,0xA14FB3F0611A767C,0x8D2605F21C160136,0xD6B71922FECC549E, + 0x37089438A5907D8B,0x0B5DA38E5803D49C,0x5A5BCC9CEA6F3CBC,0xEDAE246D3B73FFE5, + 0xD2B87E0FDE22EDCE,0x5E54ABB1CA8185EC,0x1DE7F88FE80561B9,0xAD5E1A870135A08C, + 0x2F2ADBD665CECC76,0x5780B5A782F58358,0x3EDC8A2EEDE47B3F,0xC9D95C3506BEE70F, + 0x83BE111D6C4E05EE,0xA603B90959367410,0x103C81B4809FDE5D,0x2C69B6027D0C774A, + 0x399080D7D5C87953,0x09D41E16487406B4,0xCDD63B1826505E5F,0xF99DC2F49B0298E8, + 0x9CD0540A943CB67F,0xBCA84B7F891F17C5,0x723D1DB3B78DF2A6,0x78AA6E71E73B4F2E, + 0x1433E699A071670D,0x84F21BE454620782,0x98DF3327B4D20F2F,0xF049DCE2D3769E5C, + 0xDB6C60199656EB7A,0x648746B2078B4783,0x32CD23598DCBADCF,0x1EA4955BF0C7DA85, + 0xE9A143401B9D46B5,0xFD92A5D9BBEC21B8,0xC8138C790E0B8E1B,0x2EE00B9A6D7BA562, + 0xF85712B893B7F1FC,0xEB28FED80BEA949D,0x564A65EB8A40EA4C,0x6C9988E8474A2823, + 0x4535898B121D8F2D,0xABD8C03231ACCBF4,0xBA2E91CAB9867CBD,0x7960BE3DEF8E263A, + 0x0C11A977602FD6F0,0xCB50E1AD16C93527,0xEAE22E94035FFD89,0x2866D12F5DE2CE1A, + 0xFF1B1841AB9BF390,0x9F9339DE8CFE0D43,0x964727C8C48A0BF7,0x524502C6AAAE531C, + 0x9B9C5EF3AC10B413,0x4FA2FA4942AB32A5,0x3F165A62E551122B,0xC74148DA76E6E3D7, + 0x924840E5E464B2A7,0xD372AE43D69784DA,0x233B72A105E11A86,0xA48A04914941A638, + 0xB4B68525C9DE7865,0xDDEABAACA6CF8002,0x0A9773C250B6BD88,0xC284FFBB5EBD3393, + 0x8BA0DF472C8F6A4E,0x2AEF6CB74D951C32,0x427983722A318D41,0x73F7CDFFBF389BB2, + 0x074C0AF9382C026C,0x8A6A0F0B243A035A,0x6FDAE53C5F88931F,0xC68B98967E538AC3, + 0x44FF59C71AA8E639,0xE2FCE0CE439E9229,0xA20CDE2479D8CD40,0x19E89FA2C8EBD8E9, + 0xF446BBCFF398270C,0x43B3533E2284E455,0xD82F0DCD8E945046,0x51066F12B26CE820, + 0xE73957AF6BC5426D,0x081ECE5A40C16FA0,0x3B193D4FC5BFAB7B,0x7FE66488DF174D42, + 0x0E9814EF705804D8,0x8137AC857C39D7C6,0xB1733244E185A821,0x695C3F896F11F867, + 0xF6CF0657E3EFF524,0x1AABF276D02963D5,0x2DA3664E75B91E5E,0x0289BD981077D228, + 0x90C1FD7DF413608F,0x3C5537B6FD93A917,0xAA12107E3919A2E0,0x0686DAB530996B78, + 0xDAA6B0559EE3826E,0xC34E2FF756085A87,0x6D5358A44FFF4137,0xFC587595B35948AC, + 0x7CA5095CC7D5F67E,0xFB147F6C8B754AC0,0xBFEB26AB91DDACF9,0x6896EFC567A49173, + 0xCA9A31E11E7C5C33,0xBBE44186B13315A9,0x0DDB793B689ABFE4,0x70B4A02BA7FA208E, + 0xE47A3A7B7307F951,0x8CECD5BE14A36822,0xEEED49B923B144D9,0x17708B4DB8B3DC31, + 0x6088219F2765FED3,0xB3FA8FDCF1F27A09,0x910B2D31FCA6099B,0x0F52C4A378ED6DCC, + 0x50CCBF5EBAD98134,0x6BD582117F662A4F,0x94CE9A50D4FDD9DF,0x2B25BCFB45207526, + 0x67C42B661F49FCBF,0x492420FC723259DD,0x03436DD418C2BB3C,0x1F6E4517F872B391, + 0xA08563BC69AF1F68,0xD43EA4BAEEBB86B6,0x01CAD04C08B56914,0xAC94CACB0980C998, + 0x54C3D8739A373864,0x26FEC5C02DBACAC2,0xDEA9D778BE0D3B3E,0x040F672D20EEB950, + 0xE5B0EA377BB29045,0xF30AB136CBB42560,0x62019C0737122CFB,0xE86B930C13282FA1, + 0xCC1CEB542EE5374B,0x538FD28AA21B3A08,0x1B61223AD89C0AC1,0x36C24474AD25149F, + 0x7A23D3E9F74C9D06,0xBE21F6E79968C5ED,0xCF5F868036278C77,0xF705D61BEB5A9C30, + 0x4D2B47D152DCE08D,0x5F9E7BFDC234ECF8,0x247778583DCD18EA,0x867BA67C4415D5AA, + 0x4CE1979D5A698999,0x0000000000000000,0xEC64F42133C696F1,0xB57C5569C16B1171, + 0xC1C7926F467F88AF,0x654D96FE0F3E2E97,0x15F936D5A8C40E19,0xB8A72C52A9F1AE95, + 0xA9517DAA21DB19DC,0x58D27104FA18EE94,0x5918A148F2AD8780,0x5CDD1629DAF657C4, + 0x8274C15164FB6CFA,0xD1FB13DBC6E056F2,0x7D6FD910CF609F6A,0xB63F38BDD9A9AA4D, + 0x3D9FE7FAF526C003,0x74BBC706871499DE,0xDF630734B6B8522A,0x3AD3ED03CD0AC26F, + 0xFADEAF2083C023D4,0xC00D42234ECAE1BB,0x8538CBA85CD76E96,0xC402250E6E2458EB, + 0x47BC3413026A5D05,0xAFD7A71F114272A4,0x978DF784CC3F62E3,0xB96DFC1EA144C781, + 0x21B2CF391596C8AE,0x318E4E8D950916F3,0xCE9556CC3E92E563,0x385A509BDD7D1047, + 0x358129A0B5E7AFA3,0xE6F387E363702B79,0xE0755D5653E94001,0x7BE903A5FFF9F412, + 0x12B53C2C90E80C75,0x3307F315857EC4DB,0x8FAFB86A0C61D31E,0xD9E5DD8186213952, + 0x77F8AAD29FD622E2,0x25BDA814357871FE,0x7571174A8FA1F0CA,0x137FEC60985D6561, + 0x30449EC19DBC7FE7,0xA540D4DD41F4CF2C,0xDC206AE0AE7AE916,0x5B911CD0E2DA55A8, + 0xB2305F90F947131D,0x344BF9ECBD52C6B7,0x5D17C665D2433ED0,0x18224FEEC05EB1FD, + 0x9E59E992844B6457,0x9A568EBFA4A5DD07,0xA3C60E68716DA454,0x7E2CB4C4D7A22456, + 0x87B176304CA0BCBE,0x413AEEA632F3367D,0x9915E36BBC67663B,0x40F03EEA3A465F69, + 0x1C2D28C3E0B008AD,0x4E682A054A1E5BB1,0x05C5B761285BD044,0xE1BF8D1A5B5C2915, + 0xF2C0617AC3014C74,0xB7F5E8F1D11CC359,0x63CB4C4B3FA745EF,0x9D1A84469C89DF6B, + 0xE33630824B2BFB3D,0xD5F474F6E60EEFA2,0xF58C6B83FB2D4E18,0x4676E45F0ADF3411, + 0x20781F751D23A1BA,0xBD629B3381AA7ED1,0xAE1D775319F71BB0,0xFED1C80DA32E9A84, + 0x5509083F92825170,0x29AC01635557A70E,0xA7C9694551831D04,0x8E65682604D4BA0A, + 0x11F651F8882AB749,0xD77DC96EF6793D8A,0xEF2799F52B042DCD,0x48EEF0B07A8730C9, + 0x22F1A2ED0D547392,0x6142F1D32FD097C7,0x4A674D286AF0E2E1,0x80FD7CC9748CBED2, + 0x717E7067AF4F499A,0x938290A9ECD1DBB3,0x88E3B293344DD172,0x2734158C250FA3D6 +}}; + +// Constant values for KeySchedule function +const unsigned char C[12][64] = {{ + 0xB1,0x08,0x5B,0xDA,0x1E,0xCA,0xDA,0xE9,0xEB,0xCB,0x2F,0x81,0xC0,0x65,0x7C,0x1F, + 0x2F,0x6A,0x76,0x43,0x2E,0x45,0xD0,0x16,0x71,0x4E,0xB8,0x8D,0x75,0x85,0xC4,0xFC, + 0x4B,0x7C,0xE0,0x91,0x92,0x67,0x69,0x01,0xA2,0x42,0x2A,0x08,0xA4,0x60,0xD3,0x15, + 0x05,0x76,0x74,0x36,0xCC,0x74,0x4D,0x23,0xDD,0x80,0x65,0x59,0xF2,0xA6,0x45,0x07 +},{ + 0x6F,0xA3,0xB5,0x8A,0xA9,0x9D,0x2F,0x1A,0x4F,0xE3,0x9D,0x46,0x0F,0x70,0xB5,0xD7, + 0xF3,0xFE,0xEA,0x72,0x0A,0x23,0x2B,0x98,0x61,0xD5,0x5E,0x0F,0x16,0xB5,0x01,0x31, + 0x9A,0xB5,0x17,0x6B,0x12,0xD6,0x99,0x58,0x5C,0xB5,0x61,0xC2,0xDB,0x0A,0xA7,0xCA, + 0x55,0xDD,0xA2,0x1B,0xD7,0xCB,0xCD,0x56,0xE6,0x79,0x04,0x70,0x21,0xB1,0x9B,0xB7 +},{ + 0xF5,0x74,0xDC,0xAC,0x2B,0xCE,0x2F,0xC7,0x0A,0x39,0xFC,0x28,0x6A,0x3D,0x84,0x35, + 0x06,0xF1,0x5E,0x5F,0x52,0x9C,0x1F,0x8B,0xF2,0xEA,0x75,0x14,0xB1,0x29,0x7B,0x7B, + 0xD3,0xE2,0x0F,0xE4,0x90,0x35,0x9E,0xB1,0xC1,0xC9,0x3A,0x37,0x60,0x62,0xDB,0x09, + 0xC2,0xB6,0xF4,0x43,0x86,0x7A,0xDB,0x31,0x99,0x1E,0x96,0xF5,0x0A,0xBA,0x0A,0xB2 +},{ + 0xEF,0x1F,0xDF,0xB3,0xE8,0x15,0x66,0xD2,0xF9,0x48,0xE1,0xA0,0x5D,0x71,0xE4,0xDD, + 0x48,0x8E,0x85,0x7E,0x33,0x5C,0x3C,0x7D,0x9D,0x72,0x1C,0xAD,0x68,0x5E,0x35,0x3F, + 0xA9,0xD7,0x2C,0x82,0xED,0x03,0xD6,0x75,0xD8,0xB7,0x13,0x33,0x93,0x52,0x03,0xBE, + 0x34,0x53,0xEA,0xA1,0x93,0xE8,0x37,0xF1,0x22,0x0C,0xBE,0xBC,0x84,0xE3,0xD1,0x2E +},{ + 0x4B,0xEA,0x6B,0xAC,0xAD,0x47,0x47,0x99,0x9A,0x3F,0x41,0x0C,0x6C,0xA9,0x23,0x63, + 0x7F,0x15,0x1C,0x1F,0x16,0x86,0x10,0x4A,0x35,0x9E,0x35,0xD7,0x80,0x0F,0xFF,0xBD, + 0xBF,0xCD,0x17,0x47,0x25,0x3A,0xF5,0xA3,0xDF,0xFF,0x00,0xB7,0x23,0x27,0x1A,0x16, + 0x7A,0x56,0xA2,0x7E,0xA9,0xEA,0x63,0xF5,0x60,0x17,0x58,0xFD,0x7C,0x6C,0xFE,0x57 +},{ + 0xAE,0x4F,0xAE,0xAE,0x1D,0x3A,0xD3,0xD9,0x6F,0xA4,0xC3,0x3B,0x7A,0x30,0x39,0xC0, + 0x2D,0x66,0xC4,0xF9,0x51,0x42,0xA4,0x6C,0x18,0x7F,0x9A,0xB4,0x9A,0xF0,0x8E,0xC6, + 0xCF,0xFA,0xA6,0xB7,0x1C,0x9A,0xB7,0xB4,0x0A,0xF2,0x1F,0x66,0xC2,0xBE,0xC6,0xB6, + 0xBF,0x71,0xC5,0x72,0x36,0x90,0x4F,0x35,0xFA,0x68,0x40,0x7A,0x46,0x64,0x7D,0x6E +},{ + 0xF4,0xC7,0x0E,0x16,0xEE,0xAA,0xC5,0xEC,0x51,0xAC,0x86,0xFE,0xBF,0x24,0x09,0x54, + 0x39,0x9E,0xC6,0xC7,0xE6,0xBF,0x87,0xC9,0xD3,0x47,0x3E,0x33,0x19,0x7A,0x93,0xC9, + 0x09,0x92,0xAB,0xC5,0x2D,0x82,0x2C,0x37,0x06,0x47,0x69,0x83,0x28,0x4A,0x05,0x04, + 0x35,0x17,0x45,0x4C,0xA2,0x3C,0x4A,0xF3,0x88,0x86,0x56,0x4D,0x3A,0x14,0xD4,0x93 +},{ + 0x9B,0x1F,0x5B,0x42,0x4D,0x93,0xC9,0xA7,0x03,0xE7,0xAA,0x02,0x0C,0x6E,0x41,0x41, + 0x4E,0xB7,0xF8,0x71,0x9C,0x36,0xDE,0x1E,0x89,0xB4,0x44,0x3B,0x4D,0xDB,0xC4,0x9A, + 0xF4,0x89,0x2B,0xCB,0x92,0x9B,0x06,0x90,0x69,0xD1,0x8D,0x2B,0xD1,0xA5,0xC4,0x2F, + 0x36,0xAC,0xC2,0x35,0x59,0x51,0xA8,0xD9,0xA4,0x7F,0x0D,0xD4,0xBF,0x02,0xE7,0x1E +},{ + 0x37,0x8F,0x5A,0x54,0x16,0x31,0x22,0x9B,0x94,0x4C,0x9A,0xD8,0xEC,0x16,0x5F,0xDE, + 0x3A,0x7D,0x3A,0x1B,0x25,0x89,0x42,0x24,0x3C,0xD9,0x55,0xB7,0xE0,0x0D,0x09,0x84, + 0x80,0x0A,0x44,0x0B,0xDB,0xB2,0xCE,0xB1,0x7B,0x2B,0x8A,0x9A,0xA6,0x07,0x9C,0x54, + 0x0E,0x38,0xDC,0x92,0xCB,0x1F,0x2A,0x60,0x72,0x61,0x44,0x51,0x83,0x23,0x5A,0xDB +},{ + 0xAB,0xBE,0xDE,0xA6,0x80,0x05,0x6F,0x52,0x38,0x2A,0xE5,0x48,0xB2,0xE4,0xF3,0xF3, + 0x89,0x41,0xE7,0x1C,0xFF,0x8A,0x78,0xDB,0x1F,0xFF,0xE1,0x8A,0x1B,0x33,0x61,0x03, + 0x9F,0xE7,0x67,0x02,0xAF,0x69,0x33,0x4B,0x7A,0x1E,0x6C,0x30,0x3B,0x76,0x52,0xF4, + 0x36,0x98,0xFA,0xD1,0x15,0x3B,0xB6,0xC3,0x74,0xB4,0xC7,0xFB,0x98,0x45,0x9C,0xED +},{ + 0x7B,0xCD,0x9E,0xD0,0xEF,0xC8,0x89,0xFB,0x30,0x02,0xC6,0xCD,0x63,0x5A,0xFE,0x94, + 0xD8,0xFA,0x6B,0xBB,0xEB,0xAB,0x07,0x61,0x20,0x01,0x80,0x21,0x14,0x84,0x66,0x79, + 0x8A,0x1D,0x71,0xEF,0xEA,0x48,0xB9,0xCA,0xEF,0xBA,0xCD,0x1D,0x7D,0x47,0x6E,0x98, + 0xDE,0xA2,0x59,0x4A,0xC0,0x6F,0xD8,0x5D,0x6B,0xCA,0xA4,0xCD,0x81,0xF3,0x2D,0x1B +},{ + 0x37,0x8E,0xE7,0x67,0xF1,0x16,0x31,0xBA,0xD2,0x13,0x80,0xB0,0x04,0x49,0xB1,0x7A, + 0xCD,0xA4,0x3C,0x32,0xBC,0xDF,0x1D,0x77,0xF8,0x20,0x12,0xD4,0x30,0x21,0x9F,0x9B, + 0x5D,0x80,0xEF,0x9D,0x18,0x91,0xCC,0x86,0xE7,0x1D,0xA4,0xAA,0x88,0xE1,0x28,0x52, + 0xFA,0xF4,0x17,0xD5,0xD9,0xB2,0x1B,0x99,0x48,0xBC,0x92,0x4A,0xF1,0x1B,0xD7,0x20 +}}; + + +static void AddModulo512(const void *a,const void *b,void *c) +{ + const unsigned char *A=a, *B=b; + unsigned char *C=c; + int t = 0; +#ifdef FULL_UNROLL +#define ADDBYTE_8(i) t = A[i] + B[i] + (t >> 8); C[i] = t & 0xFF; + + ADDBYTE_8(63) + ADDBYTE_8(62) + ADDBYTE_8(61) + ADDBYTE_8(60) + ADDBYTE_8(59) + ADDBYTE_8(58) + ADDBYTE_8(57) + ADDBYTE_8(56) + ADDBYTE_8(55) + ADDBYTE_8(54) + ADDBYTE_8(53) + ADDBYTE_8(52) + ADDBYTE_8(51) + ADDBYTE_8(50) + ADDBYTE_8(49) + ADDBYTE_8(48) + ADDBYTE_8(47) + ADDBYTE_8(46) + ADDBYTE_8(45) + ADDBYTE_8(44) + ADDBYTE_8(43) + ADDBYTE_8(42) + ADDBYTE_8(41) + ADDBYTE_8(40) + ADDBYTE_8(39) + ADDBYTE_8(38) + ADDBYTE_8(37) + ADDBYTE_8(36) + ADDBYTE_8(35) + ADDBYTE_8(34) + ADDBYTE_8(33) + ADDBYTE_8(32) + ADDBYTE_8(31) + ADDBYTE_8(30) + ADDBYTE_8(29) + ADDBYTE_8(28) + ADDBYTE_8(27) + ADDBYTE_8(26) + ADDBYTE_8(25) + ADDBYTE_8(24) + ADDBYTE_8(23) + ADDBYTE_8(22) + ADDBYTE_8(21) + ADDBYTE_8(20) + ADDBYTE_8(19) + ADDBYTE_8(18) + ADDBYTE_8(17) + ADDBYTE_8(16) + ADDBYTE_8(15) + ADDBYTE_8(14) + ADDBYTE_8(13) + ADDBYTE_8(12) + ADDBYTE_8(11) + ADDBYTE_8(10) + ADDBYTE_8(9) + ADDBYTE_8(8) + ADDBYTE_8(7) + ADDBYTE_8(6) + ADDBYTE_8(5) + ADDBYTE_8(4) + ADDBYTE_8(3) + ADDBYTE_8(2) + ADDBYTE_8(1) + ADDBYTE_8(0) + +#else + int i = 0; + + for(i=63;i>=0;i--) + { + t = A[i] + B[i] + (t >> 8); + C[i] = t & 0xFF; + } +#endif +} + +static void AddXor512(const void *a,const void *b,void *c) +{ + const unsigned long long *A=a, *B=b; + unsigned long long *C=c; +#ifdef FULL_UNROLL + C[0] = A[0] ^ B[0]; + C[1] = A[1] ^ B[1]; + C[2] = A[2] ^ B[2]; + C[3] = A[3] ^ B[3]; + C[4] = A[4] ^ B[4]; + C[5] = A[5] ^ B[5]; + C[6] = A[6] ^ B[6]; + C[7] = A[7] ^ B[7]; +#else + int i = 0; + + for(i=0; i<8; i++) { + C[i] = A[i] ^ B[i]; + } +#endif +} + +static void F(unsigned char *state) +{ + unsigned long long return_state[8]; + register unsigned long long r = 0; + r ^= TG[0][state[56]]; + r ^= TG[1][state[48]]; + r ^= TG[2][state[40]]; + r ^= TG[3][state[32]]; + r ^= TG[4][state[24]]; + r ^= TG[5][state[16]]; + r ^= TG[6][state[8]]; + r ^= TG[7][state[0]]; + return_state[0] = r; + r = 0; + + r ^= TG[0][state[57]]; + r ^= TG[1][state[49]]; + r ^= TG[2][state[41]]; + r ^= TG[3][state[33]]; + r ^= TG[4][state[25]]; + r ^= TG[5][state[17]]; + r ^= TG[6][state[9]]; + r ^= TG[7][state[1]]; + return_state[1] = r; + r = 0; + + r ^= TG[0][state[58]]; + r ^= TG[1][state[50]]; + r ^= TG[2][state[42]]; + r ^= TG[3][state[34]]; + r ^= TG[4][state[26]]; + r ^= TG[5][state[18]]; + r ^= TG[6][state[10]]; + r ^= TG[7][state[2]]; + return_state[2] = r; + r = 0; + + r ^= TG[0][state[59]]; + r ^= TG[1][state[51]]; + r ^= TG[2][state[43]]; + r ^= TG[3][state[35]]; + r ^= TG[4][state[27]]; + r ^= TG[5][state[19]]; + r ^= TG[6][state[11]]; + r ^= TG[7][state[3]]; + return_state[3] = r; + r = 0; + + r ^= TG[0][state[60]]; + r ^= TG[1][state[52]]; + r ^= TG[2][state[44]]; + r ^= TG[3][state[36]]; + r ^= TG[4][state[28]]; + r ^= TG[5][state[20]]; + r ^= TG[6][state[12]]; + r ^= TG[7][state[4]]; + return_state[4] = r; + r = 0; + + r ^= TG[0][state[61]]; + r ^= TG[1][state[53]]; + r ^= TG[2][state[45]]; + r ^= TG[3][state[37]]; + r ^= TG[4][state[29]]; + r ^= TG[5][state[21]]; + r ^= TG[6][state[13]]; + r ^= TG[7][state[5]]; + return_state[5] = r; + r = 0; + + r ^= TG[0][state[62]]; + r ^= TG[1][state[54]]; + r ^= TG[2][state[46]]; + r ^= TG[3][state[38]]; + r ^= TG[4][state[30]]; + r ^= TG[5][state[22]]; + r ^= TG[6][state[14]]; + r ^= TG[7][state[6]]; + return_state[6] = r; + r = 0; + + r ^= TG[0][state[63]]; + r ^= TG[1][state[55]]; + r ^= TG[2][state[47]]; + r ^= TG[3][state[39]]; + r ^= TG[4][state[31]]; + r ^= TG[5][state[23]]; + r ^= TG[6][state[15]]; + r ^= TG[7][state[7]]; + return_state[7] = r; + + memcpy(state,(unsigned char*)return_state,64); +} + +#define KeySchedule(K,i) AddXor512(K,C[i],K); F(K); + +static void E(unsigned char *K,const unsigned char *m, unsigned char *state) +{ +#ifdef FULL_UNROLL + AddXor512(m,K,state); + + F(state); + KeySchedule(K,0); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,1); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,2); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,3); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,4); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,5); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,6); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,7); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,8); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,9); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,10); + AddXor512(state,K,state); + + F(state); + KeySchedule(K,11); + AddXor512(state,K,state); +#else + int i = 0; + + AddXor512(m,K,state); + + for(i=0;i<12;i++) { + F(state); + KeySchedule(K,i); + AddXor512(state,K,state); + } +#endif +} + +static void g_N(const unsigned char *N,unsigned char *h,const unsigned char *m) +{ + unsigned char t[64], K[64]; + + AddXor512(N,h,K); + + F(K); + + E(K,m,t); + + AddXor512(t,h,t); + AddXor512(t,m,h); +} + +static void hash_X(unsigned char *IV,const unsigned char *message,unsigned long long length,unsigned char *out) +{ + unsigned char v512[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, + 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,0x02,0x00 + }; + unsigned char v0[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, + 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 + }; + unsigned char Sigma[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, + 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 + }; + unsigned char N[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, + 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 + }; + unsigned char m[64], *hash = IV; + unsigned long long len = length; + + // Stage 2 + while (len >= 512) + { + memcpy(m, message + len/8 - 63 - ( (len & 0x7) == 0 ), 64); + + g_N(N,hash,m); + AddModulo512(N,v512,N); + AddModulo512(Sigma,m,Sigma); + len -= 512; + } + + memset(m,0,64); + memcpy(m + 63 - len/8 + ( (len & 0x7) == 0 ), message, len/8 + 1 - ( (len & 0x7) == 0 )); + + // Stage 3 + m[ 63 - len/8 ] |= (1 << (len & 0x7)); + + g_N(N,hash,m); + v512[63] = len & 0xFF; + v512[62] = (unsigned char) (len >> 8); + AddModulo512(N,v512,N); + + AddModulo512(Sigma,m,Sigma); + + g_N(v0,hash,N); + g_N(v0,hash,Sigma); + + memcpy(out, hash, 64); +} + +static void hash_512(const unsigned char *message, unsigned long long length, unsigned char *out) +{ + unsigned char IV[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, + 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 + }; + + hash_X(IV,message,length,out); +} + +static void hash_256(const unsigned char *message, unsigned long long length, unsigned char *out) +{ + unsigned char IV[64] = { + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 + }; + unsigned char hash[64]; + + hash_X(IV,message,length,hash); + + memcpy(out,hash,32); +} + + +/* exported functions, to rename (streebog) */ + + +void sph_gost256_init(void *cc) +{ +} + +void sph_gost256(void *cc, const void *data, size_t len) +{ + hash_256(data, 8*len, cc); +} + +void sph_gost256_close(void *cc, void *dst) +{ + memcpy(dst, cc, 32); +} + +void sph_gost256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ +} + +void sph_gost512_init(void *cc) +{ +} + +void sph_gost512(void *cc, const void *data, size_t len) +{ + hash_512(data, 8*len, cc); +} + +void sph_gost512_close(void *cc, void *dst) +{ + memcpy(dst, cc, 64); +} + +void sph_gost512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ +} + + +#ifdef __cplusplus +} +#endif diff --git a/sha3/gost_streebog.h b/sha3/gost_streebog.h new file mode 100644 index 000000000..aa8f69d0d --- /dev/null +++ b/sha3/gost_streebog.h @@ -0,0 +1,185 @@ +/* $Id: sph_gost.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * GOST interface. This is the interface for GOST R 12 with the + * recommended parameters for SHA-3, with output lengths 256 + * and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_gost.h + * @author Mish + */ + +#ifndef SPH_GOST_H__ +#define SPH_GOST_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for GOST-256. + */ +#define SPH_SIZE_gost256 256 + +/** + * Output size (in bits) for GOST-512. + */ +#define SPH_SIZE_gost512 512 + +/** + * This structure is a context for Keccak computations: it contains the + * intermediate values and some data from the last entered block. Once a + * GOST computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running GOST computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ + +/** + * This structure is a context for Gost-256 computations. + */ + +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[3][8]; +#endif +} sph_gost256_context; + +/** + * This structure is a context for Gost-512 computations. + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[5][8]; +#endif +} sph_gost512_context; + + +/** + * Initialize a GOST-256 context. This process performs no memory allocation. + * + * @param cc the GOST-256 context (pointer to a + * sph_gost256_context) + */ +void sph_gost256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Gost-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_gost256(void *cc, const void *data, size_t len); + +/** + * Terminate the current GOST-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the GOST-256 context + * @param dst the destination buffer + */ +void sph_gost256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the GOST-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_gost256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Gost-512 context. This process performs no memory allocation. + * + * @param cc the GOST-512 context (pointer to a + * sph_gost512_context) + */ +void sph_gost512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the GOST-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_gost512(void *cc, const void *data, size_t len); + +/** + * Terminate the current GOST-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the GOST-512 context + * @param dst the destination buffer + */ +void sph_gost512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the GOST-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_gost512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sha3/haval_helper.c b/sha3/haval_helper.c new file mode 100644 index 000000000..c5080f75d --- /dev/null +++ b/sha3/haval_helper.c @@ -0,0 +1,195 @@ +/* $Id: haval_helper.c 218 2010-06-08 17:06:34Z tp $ */ +/* + * Helper code, included (three times !) by HAVAL implementation. + * + * TODO: try to merge this with md_helper.c. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#undef SPH_XCAT +#define SPH_XCAT(a, b) SPH_XCAT_(a, b) +#undef SPH_XCAT_ +#define SPH_XCAT_(a, b) a ## b + +static void +#ifdef SPH_UPTR +SPH_XCAT(SPH_XCAT(haval, PASSES), _short) +#else +SPH_XCAT(haval, PASSES) +#endif +(sph_haval_context *sc, const void *data, size_t len) +{ + unsigned current; + +#if SPH_64 + current = (unsigned)sc->count & 127U; +#else + current = (unsigned)sc->count_low & 127U; +#endif + while (len > 0) { + unsigned clen; +#if !SPH_64 + sph_u32 clow, clow2; +#endif + + clen = 128U - current; + if (clen > len) + clen = (unsigned) len; + memcpy(sc->buf + current, data, clen); + data = (const unsigned char *)data + clen; + current += clen; + len -= clen; + if (current == 128U) { + DSTATE; + IN_PREPARE(sc->buf); + + RSTATE; + SPH_XCAT(CORE, PASSES)(INW); + WSTATE; + current = 0; + } +#if SPH_64 + sc->count += clen; +#else + clow = sc->count_low; + clow2 = SPH_T32(clow + clen); + sc->count_low = clow2; + if (clow2 < clow) + sc->count_high ++; +#endif + } +} + +#ifdef SPH_UPTR +static void +SPH_XCAT(haval, PASSES)(sph_haval_context *sc, const void *data, size_t len) +{ + unsigned current; + size_t orig_len; +#if !SPH_64 + sph_u32 clow, clow2; +#endif + DSTATE; + + if (len < 256U) { + SPH_XCAT(SPH_XCAT(haval, PASSES), _short)(sc, data, len); + return; + } +#if SPH_64 + current = (unsigned)sc->count & 127U; +#else + current = (unsigned)sc->count_low & 127U; +#endif + if (current > 0) { + unsigned clen; + + clen = 128U - current; + SPH_XCAT(SPH_XCAT(haval, PASSES), _short)(sc, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + } +#if !SPH_UNALIGNED + if (((SPH_UPTR)data & 3U) != 0) { + SPH_XCAT(SPH_XCAT(haval, PASSES), _short)(sc, data, len); + return; + } +#endif + orig_len = len; + RSTATE; + while (len >= 128U) { + IN_PREPARE(data); + + SPH_XCAT(CORE, PASSES)(INW); + data = (const unsigned char *)data + 128U; + len -= 128U; + } + WSTATE; + if (len > 0) + memcpy(sc->buf, data, len); +#if SPH_64 + sc->count += (sph_u64)orig_len; +#else + clow = sc->count_low; + clow2 = SPH_T32(clow + orig_len); + sc->count_low = clow2; + if (clow2 < clow) + sc->count_high ++; + orig_len >>= 12; + orig_len >>= 10; + orig_len >>= 10; + sc->count_high += orig_len; +#endif +} +#endif + +static void +SPH_XCAT(SPH_XCAT(haval, PASSES), _close)(sph_haval_context *sc, + unsigned ub, unsigned n, void *dst) +{ + unsigned current; + DSTATE; + +#if SPH_64 + current = (unsigned)sc->count & 127U; +#else + current = (unsigned)sc->count_low & 127U; +#endif + sc->buf[current ++] = (0x01 << n) | ((ub & 0xFF) >> (8 - n)); + RSTATE; + if (current > 118U) { + memset(sc->buf + current, 0, 128U - current); + + do { + IN_PREPARE(sc->buf); + + SPH_XCAT(CORE, PASSES)(INW); + } while (0); + current = 0; + } + memset(sc->buf + current, 0, 118U - current); + sc->buf[118] = 0x01 | (PASSES << 3); + sc->buf[119] = sc->olen << 3; +#if SPH_64 + sph_enc64le_aligned(sc->buf + 120, SPH_T64(sc->count << 3)); +#else + sph_enc32le_aligned(sc->buf + 120, SPH_T32(sc->count_low << 3)); + sph_enc32le_aligned(sc->buf + 124, + SPH_T32((sc->count_high << 3) | (sc->count_low >> 29))); +#endif + do { + IN_PREPARE(sc->buf); + + SPH_XCAT(CORE, PASSES)(INW); + } while (0); + + WSTATE; + haval_out(sc, dst); + haval_init(sc, sc->olen, sc->passes); +} + diff --git a/sha3/sph_x15_helper.c b/sha3/md_helper.c similarity index 99% rename from sha3/sph_x15_helper.c rename to sha3/md_helper.c index 5384f03f7..3ae23d76a 100644 --- a/sha3/sph_x15_helper.c +++ b/sha3/md_helper.c @@ -129,7 +129,7 @@ SPH_XCAT(sph_, HASH)(void *cc, const void *data, size_t len) #endif { SPH_XCAT(sph_, SPH_XCAT(HASH, _context)) *sc; - unsigned current; + size_t current; sc = cc; #if SPH_64 @@ -138,7 +138,7 @@ SPH_XCAT(sph_, HASH)(void *cc, const void *data, size_t len) current = (unsigned)sc->count_low & (SPH_BLEN - 1U); #endif while (len > 0) { - unsigned clen; + size_t clen; #if !SPH_64 sph_u32 clow, clow2; #endif diff --git a/sha3/mod_blakecoin.c b/sha3/mod_blakecoin.c new file mode 100644 index 000000000..7b597f94d --- /dev/null +++ b/sha3/mod_blakecoin.c @@ -0,0 +1,531 @@ +/* $Id: blake.c 252 2011-06-07 17:55:14Z tp $ */ +/* + * BLAKECOIN implementation. (Stripped to 256 bits only) + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + * @author Tanguy Pruvot (cpuminer implementation) + */ + +#include +#include +#include + +#include "sph_blake.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 IV256[8] = { + SPH_C32(0x6A09E667), SPH_C32(0xBB67AE85), + SPH_C32(0x3C6EF372), SPH_C32(0xA54FF53A), + SPH_C32(0x510E527F), SPH_C32(0x9B05688C), + SPH_C32(0x1F83D9AB), SPH_C32(0x5BE0CD19) +}; + +#define Z00 0 +#define Z01 1 +#define Z02 2 +#define Z03 3 +#define Z04 4 +#define Z05 5 +#define Z06 6 +#define Z07 7 +#define Z08 8 +#define Z09 9 +#define Z0A A +#define Z0B B +#define Z0C C +#define Z0D D +#define Z0E E +#define Z0F F + +#define Z10 E +#define Z11 A +#define Z12 4 +#define Z13 8 +#define Z14 9 +#define Z15 F +#define Z16 D +#define Z17 6 +#define Z18 1 +#define Z19 C +#define Z1A 0 +#define Z1B 2 +#define Z1C B +#define Z1D 7 +#define Z1E 5 +#define Z1F 3 + +#define Z20 B +#define Z21 8 +#define Z22 C +#define Z23 0 +#define Z24 5 +#define Z25 2 +#define Z26 F +#define Z27 D +#define Z28 A +#define Z29 E +#define Z2A 3 +#define Z2B 6 +#define Z2C 7 +#define Z2D 1 +#define Z2E 9 +#define Z2F 4 + +#define Z30 7 +#define Z31 9 +#define Z32 3 +#define Z33 1 +#define Z34 D +#define Z35 C +#define Z36 B +#define Z37 E +#define Z38 2 +#define Z39 6 +#define Z3A 5 +#define Z3B A +#define Z3C 4 +#define Z3D 0 +#define Z3E F +#define Z3F 8 + +#define Z40 9 +#define Z41 0 +#define Z42 5 +#define Z43 7 +#define Z44 2 +#define Z45 4 +#define Z46 A +#define Z47 F +#define Z48 E +#define Z49 1 +#define Z4A B +#define Z4B C +#define Z4C 6 +#define Z4D 8 +#define Z4E 3 +#define Z4F D + +#define Z50 2 +#define Z51 C +#define Z52 6 +#define Z53 A +#define Z54 0 +#define Z55 B +#define Z56 8 +#define Z57 3 +#define Z58 4 +#define Z59 D +#define Z5A 7 +#define Z5B 5 +#define Z5C F +#define Z5D E +#define Z5E 1 +#define Z5F 9 + +#define Z60 C +#define Z61 5 +#define Z62 1 +#define Z63 F +#define Z64 E +#define Z65 D +#define Z66 4 +#define Z67 A +#define Z68 0 +#define Z69 7 +#define Z6A 6 +#define Z6B 3 +#define Z6C 9 +#define Z6D 2 +#define Z6E 8 +#define Z6F B + +#define Z70 D +#define Z71 B +#define Z72 7 +#define Z73 E +#define Z74 C +#define Z75 1 +#define Z76 3 +#define Z77 9 +#define Z78 5 +#define Z79 0 +#define Z7A F +#define Z7B 4 +#define Z7C 8 +#define Z7D 6 +#define Z7E 2 +#define Z7F A + +#define Z80 6 +#define Z81 F +#define Z82 E +#define Z83 9 +#define Z84 B +#define Z85 3 +#define Z86 0 +#define Z87 8 +#define Z88 C +#define Z89 2 +#define Z8A D +#define Z8B 7 +#define Z8C 1 +#define Z8D 4 +#define Z8E A +#define Z8F 5 + +#define Z90 A +#define Z91 2 +#define Z92 8 +#define Z93 4 +#define Z94 7 +#define Z95 6 +#define Z96 1 +#define Z97 5 +#define Z98 F +#define Z99 B +#define Z9A 9 +#define Z9B E +#define Z9C 3 +#define Z9D C +#define Z9E D +#define Z9F 0 + +#define Mx(r, i) Mx_(Z ## r ## i) +#define Mx_(n) Mx__(n) +#define Mx__(n) M ## n + +#define CSx(r, i) CSx_(Z ## r ## i) +#define CSx_(n) CSx__(n) +#define CSx__(n) CS ## n + +#define CS0 SPH_C32(0x243F6A88) +#define CS1 SPH_C32(0x85A308D3) +#define CS2 SPH_C32(0x13198A2E) +#define CS3 SPH_C32(0x03707344) +#define CS4 SPH_C32(0xA4093822) +#define CS5 SPH_C32(0x299F31D0) +#define CS6 SPH_C32(0x082EFA98) +#define CS7 SPH_C32(0xEC4E6C89) +#define CS8 SPH_C32(0x452821E6) +#define CS9 SPH_C32(0x38D01377) +#define CSA SPH_C32(0xBE5466CF) +#define CSB SPH_C32(0x34E90C6C) +#define CSC SPH_C32(0xC0AC29B7) +#define CSD SPH_C32(0xC97C50DD) +#define CSE SPH_C32(0x3F84D5B5) +#define CSF SPH_C32(0xB5470917) + +#if SPH_64 + +#define CBx(r, i) CBx_(Z ## r ## i) +#define CBx_(n) CBx__(n) +#define CBx__(n) CB ## n + +#define CB0 SPH_C64(0x243F6A8885A308D3) +#define CB1 SPH_C64(0x13198A2E03707344) +#define CB2 SPH_C64(0xA4093822299F31D0) +#define CB3 SPH_C64(0x082EFA98EC4E6C89) +#define CB4 SPH_C64(0x452821E638D01377) +#define CB5 SPH_C64(0xBE5466CF34E90C6C) +#define CB6 SPH_C64(0xC0AC29B7C97C50DD) +#define CB7 SPH_C64(0x3F84D5B5B5470917) +#define CB8 SPH_C64(0x9216D5D98979FB1B) +#define CB9 SPH_C64(0xD1310BA698DFB5AC) +#define CBA SPH_C64(0x2FFD72DBD01ADFB7) +#define CBB SPH_C64(0xB8E1AFED6A267E96) +#define CBC SPH_C64(0xBA7C9045F12C7F99) +#define CBD SPH_C64(0x24A19947B3916CF7) +#define CBE SPH_C64(0x0801F2E2858EFC16) +#define CBF SPH_C64(0x636920D871574E69) + +#endif + +#define GS(m0, m1, c0, c1, a, b, c, d) do { \ + a = SPH_T32(a + b + (m0 ^ c1)); \ + d = SPH_ROTR32(d ^ a, 16); \ + c = SPH_T32(c + d); \ + b = SPH_ROTR32(b ^ c, 12); \ + a = SPH_T32(a + b + (m1 ^ c0)); \ + d = SPH_ROTR32(d ^ a, 8); \ + c = SPH_T32(c + d); \ + b = SPH_ROTR32(b ^ c, 7); \ + } while (0) + +#define ROUND_S(r) do { \ + GS(Mx(r, 0), Mx(r, 1), CSx(r, 0), CSx(r, 1), V0, V4, V8, VC); \ + GS(Mx(r, 2), Mx(r, 3), CSx(r, 2), CSx(r, 3), V1, V5, V9, VD); \ + GS(Mx(r, 4), Mx(r, 5), CSx(r, 4), CSx(r, 5), V2, V6, VA, VE); \ + GS(Mx(r, 6), Mx(r, 7), CSx(r, 6), CSx(r, 7), V3, V7, VB, VF); \ + GS(Mx(r, 8), Mx(r, 9), CSx(r, 8), CSx(r, 9), V0, V5, VA, VF); \ + GS(Mx(r, A), Mx(r, B), CSx(r, A), CSx(r, B), V1, V6, VB, VC); \ + GS(Mx(r, C), Mx(r, D), CSx(r, C), CSx(r, D), V2, V7, V8, VD); \ + GS(Mx(r, E), Mx(r, F), CSx(r, E), CSx(r, F), V3, V4, V9, VE); \ + } while (0) + +#define DECL_STATE32 \ + sph_u32 H0, H1, H2, H3, H4, H5, H6, H7; \ + sph_u32 S0, S1, S2, S3, T0, T1; + +#define READ_STATE32(state) do { \ + H0 = (state)->H[0]; \ + H1 = (state)->H[1]; \ + H2 = (state)->H[2]; \ + H3 = (state)->H[3]; \ + H4 = (state)->H[4]; \ + H5 = (state)->H[5]; \ + H6 = (state)->H[6]; \ + H7 = (state)->H[7]; \ + S0 = (state)->S[0]; \ + S1 = (state)->S[1]; \ + S2 = (state)->S[2]; \ + S3 = (state)->S[3]; \ + T0 = (state)->T0; \ + T1 = (state)->T1; \ + } while (0) + +#define WRITE_STATE32(state) do { \ + (state)->H[0] = H0; \ + (state)->H[1] = H1; \ + (state)->H[2] = H2; \ + (state)->H[3] = H3; \ + (state)->H[4] = H4; \ + (state)->H[5] = H5; \ + (state)->H[6] = H6; \ + (state)->H[7] = H7; \ + (state)->S[0] = S0; \ + (state)->S[1] = S1; \ + (state)->S[2] = S2; \ + (state)->S[3] = S3; \ + (state)->T0 = T0; \ + (state)->T1 = T1; \ + } while (0) + +#define BLAKE32_ROUNDS 8 + +#define COMPRESS32 do { \ + sph_u32 M0, M1, M2, M3, M4, M5, M6, M7; \ + sph_u32 M8, M9, MA, MB, MC, MD, ME, MF; \ + sph_u32 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u32 V8, V9, VA, VB, VC, VD, VE, VF; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CS0; \ + V9 = S1 ^ CS1; \ + VA = S2 ^ CS2; \ + VB = S3 ^ CS3; \ + VC = T0 ^ CS4; \ + VD = T0 ^ CS5; \ + VE = T1 ^ CS6; \ + VF = T1 ^ CS7; \ + M0 = sph_dec32be_aligned(buf + 0); \ + M1 = sph_dec32be_aligned(buf + 4); \ + M2 = sph_dec32be_aligned(buf + 8); \ + M3 = sph_dec32be_aligned(buf + 12); \ + M4 = sph_dec32be_aligned(buf + 16); \ + M5 = sph_dec32be_aligned(buf + 20); \ + M6 = sph_dec32be_aligned(buf + 24); \ + M7 = sph_dec32be_aligned(buf + 28); \ + M8 = sph_dec32be_aligned(buf + 32); \ + M9 = sph_dec32be_aligned(buf + 36); \ + MA = sph_dec32be_aligned(buf + 40); \ + MB = sph_dec32be_aligned(buf + 44); \ + MC = sph_dec32be_aligned(buf + 48); \ + MD = sph_dec32be_aligned(buf + 52); \ + ME = sph_dec32be_aligned(buf + 56); \ + MF = sph_dec32be_aligned(buf + 60); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + ROUND_S(4); \ + ROUND_S(5); \ + ROUND_S(6); \ + ROUND_S(7); \ + if (BLAKE32_ROUNDS == 14) { \ + ROUND_S(8); \ + ROUND_S(9); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + } \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + + +static const sph_u32 salt_zero_small[4] = { 0, 0, 0, 0 }; + +static void +blake32_init(sph_blake_small_context *sc, + const sph_u32 *iv, const sph_u32 *salt) +{ + memcpy(sc->H, iv, 8 * sizeof(sph_u32)); + memcpy(sc->S, salt, 4 * sizeof(sph_u32)); + sc->T0 = sc->T1 = 0; + sc->ptr = 0; +} + +static void +blake32(sph_blake_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE32 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE32(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((T0 = SPH_T32(T0 + 512)) < 512) + T1 = SPH_T32(T1 + 1); + COMPRESS32; + ptr = 0; + } + } + WRITE_STATE32(sc); + sc->ptr = ptr; +} + +static void +blake32_close(sph_blake_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + union { + unsigned char buf[64]; + sph_u32 dummy; + } u; + size_t ptr, k; + unsigned bit_len; + unsigned z; + sph_u32 th, tl; + unsigned char *out; + + ptr = sc->ptr; + bit_len = ((unsigned)ptr << 3) + n; + z = 0x80 >> n; + u.buf[ptr] = ((ub & -z) | z) & 0xFF; + tl = sc->T0 + bit_len; + th = sc->T1; + if (ptr == 0 && n == 0) { + sc->T0 = SPH_C32(0xFFFFFE00); + sc->T1 = SPH_C32(0xFFFFFFFF); + } else if (sc->T0 == 0) { + sc->T0 = SPH_C32(0xFFFFFE00) + bit_len; + sc->T1 = SPH_T32(sc->T1 - 1); + } else { + sc->T0 -= 512 - bit_len; + } + if (bit_len <= 446) { + memset(u.buf + ptr + 1, 0, 55 - ptr); + if (out_size_w32 == 8) + u.buf[55] |= 1; + sph_enc32be_aligned(u.buf + 56, th); + sph_enc32be_aligned(u.buf + 60, tl); + blake32(sc, u.buf + ptr, 64 - ptr); + } else { + memset(u.buf + ptr + 1, 0, 63 - ptr); + blake32(sc, u.buf + ptr, 64 - ptr); + sc->T0 = SPH_C32(0xFFFFFE00); + sc->T1 = SPH_C32(0xFFFFFFFF); + memset(u.buf, 0, 56); + if (out_size_w32 == 8) + u.buf[55] = 1; + sph_enc32be_aligned(u.buf + 56, th); + sph_enc32be_aligned(u.buf + 60, tl); + blake32(sc, u.buf, 64); + } + out = dst; + for (k = 0; k < out_size_w32; k ++) + sph_enc32be(out + (k << 2), sc->H[k]); +} + +void +blakecoin_init(void *cc) +{ + blake32_init(cc, IV256, salt_zero_small); +} + +void +blakecoin(void *cc, const void *data, size_t len) +{ + blake32(cc, data, len); +} + +static void +blakecoin_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake32_close(cc, ub, n, dst, 8); + blakecoin_init(cc); +} + +void +blakecoin_close(void *cc, void *dst) +{ + blakecoin_addbits_and_close(cc, 0, 0, dst); +} + +#ifdef __cplusplus +} +#endif diff --git a/sha3/sph_blake.c b/sha3/sph_blake.c index d8a651e43..8a3270216 100644 --- a/sha3/sph_blake.c +++ b/sha3/sph_blake.c @@ -509,6 +509,11 @@ static const sph_u64 CB[16] = { (state)->T1 = T1; \ } while (0) +//#define BLAKE32_ROUNDS 8 +#ifndef BLAKE32_ROUNDS +#define BLAKE32_ROUNDS 14 +#endif + #if SPH_COMPACT_BLAKE_32 #define COMPRESS32 do { \ @@ -548,7 +553,7 @@ static const sph_u64 CB[16] = { M[0xD] = sph_dec32be_aligned(buf + 52); \ M[0xE] = sph_dec32be_aligned(buf + 56); \ M[0xF] = sph_dec32be_aligned(buf + 60); \ - for (r = 0; r < 8; r ++) \ + for (r = 0; r < BLAKE32_ROUNDS; r ++) \ ROUND_S(r); \ H0 ^= S0 ^ V0 ^ V8; \ H1 ^= S1 ^ V1 ^ V9; \ @@ -607,6 +612,14 @@ static const sph_u64 CB[16] = { ROUND_S(5); \ ROUND_S(6); \ ROUND_S(7); \ + if (BLAKE32_ROUNDS == 14) { \ + ROUND_S(8); \ + ROUND_S(9); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + } \ H0 ^= S0 ^ V0 ^ V8; \ H1 ^= S1 ^ V1 ^ V9; \ H2 ^= S2 ^ V2 ^ VA; \ diff --git a/sha3/sph_haval.c b/sha3/sph_haval.c new file mode 100644 index 000000000..90922b638 --- /dev/null +++ b/sha3/sph_haval.c @@ -0,0 +1,975 @@ +/* $Id: haval.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * HAVAL implementation. + * + * The HAVAL reference paper is of questionable clarity with regards to + * some details such as endianness of bits within a byte, bytes within + * a 32-bit word, or the actual ordering of words within a stream of + * words. This implementation has been made compatible with the reference + * implementation available on: http://labs.calyptix.com/haval.php + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_haval.h" + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_HAVAL +#define SPH_SMALL_FOOTPRINT_HAVAL 1 +#endif + +/* + * Basic definition from the reference paper. + * +#define F1(x6, x5, x4, x3, x2, x1, x0) \ + (((x1) & (x4)) ^ ((x2) & (x5)) ^ ((x3) & (x6)) ^ ((x0) & (x1)) ^ (x0)) + * + */ + +#define F1(x6, x5, x4, x3, x2, x1, x0) \ + (((x1) & ((x0) ^ (x4))) ^ ((x2) & (x5)) ^ ((x3) & (x6)) ^ (x0)) + +/* + * Basic definition from the reference paper. + * +#define F2(x6, x5, x4, x3, x2, x1, x0) \ + (((x1) & (x2) & (x3)) ^ ((x2) & (x4) & (x5)) ^ ((x1) & (x2)) \ + ^ ((x1) & (x4)) ^ ((x2) & (x6)) ^ ((x3) & (x5)) \ + ^ ((x4) & (x5)) ^ ((x0) & (x2)) ^ (x0)) + * + */ + +#define F2(x6, x5, x4, x3, x2, x1, x0) \ + (((x2) & (((x1) & ~(x3)) ^ ((x4) & (x5)) ^ (x6) ^ (x0))) \ + ^ ((x4) & ((x1) ^ (x5))) ^ ((x3 & (x5)) ^ (x0))) + +/* + * Basic definition from the reference paper. + * +#define F3(x6, x5, x4, x3, x2, x1, x0) \ + (((x1) & (x2) & (x3)) ^ ((x1) & (x4)) ^ ((x2) & (x5)) \ + ^ ((x3) & (x6)) ^ ((x0) & (x3)) ^ (x0)) + * + */ + +#define F3(x6, x5, x4, x3, x2, x1, x0) \ + (((x3) & (((x1) & (x2)) ^ (x6) ^ (x0))) \ + ^ ((x1) & (x4)) ^ ((x2) & (x5)) ^ (x0)) + +/* + * Basic definition from the reference paper. + * +#define F4(x6, x5, x4, x3, x2, x1, x0) \ + (((x1) & (x2) & (x3)) ^ ((x2) & (x4) & (x5)) ^ ((x3) & (x4) & (x6)) \ + ^ ((x1) & (x4)) ^ ((x2) & (x6)) ^ ((x3) & (x4)) ^ ((x3) & (x5)) \ + ^ ((x3) & (x6)) ^ ((x4) & (x5)) ^ ((x4) & (x6)) ^ ((x0) & (x4)) ^ (x0)) + * + */ + +#define F4(x6, x5, x4, x3, x2, x1, x0) \ + (((x3) & (((x1) & (x2)) ^ ((x4) | (x6)) ^ (x5))) \ + ^ ((x4) & ((~(x2) & (x5)) ^ (x1) ^ (x6) ^ (x0))) \ + ^ ((x2) & (x6)) ^ (x0)) + +/* + * Basic definition from the reference paper. + * +#define F5(x6, x5, x4, x3, x2, x1, x0) \ + (((x1) & (x4)) ^ ((x2) & (x5)) ^ ((x3) & (x6)) \ + ^ ((x0) & (x1) & (x2) & (x3)) ^ ((x0) & (x5)) ^ (x0)) + * + */ + +#define F5(x6, x5, x4, x3, x2, x1, x0) \ + (((x0) & ~(((x1) & (x2) & (x3)) ^ (x5))) \ + ^ ((x1) & (x4)) ^ ((x2) & (x5)) ^ ((x3) & (x6))) + +/* + * The macros below integrate the phi() permutations, depending on the + * pass and the total number of passes. + */ + +#define FP3_1(x6, x5, x4, x3, x2, x1, x0) \ + F1(x1, x0, x3, x5, x6, x2, x4) +#define FP3_2(x6, x5, x4, x3, x2, x1, x0) \ + F2(x4, x2, x1, x0, x5, x3, x6) +#define FP3_3(x6, x5, x4, x3, x2, x1, x0) \ + F3(x6, x1, x2, x3, x4, x5, x0) + +#define FP4_1(x6, x5, x4, x3, x2, x1, x0) \ + F1(x2, x6, x1, x4, x5, x3, x0) +#define FP4_2(x6, x5, x4, x3, x2, x1, x0) \ + F2(x3, x5, x2, x0, x1, x6, x4) +#define FP4_3(x6, x5, x4, x3, x2, x1, x0) \ + F3(x1, x4, x3, x6, x0, x2, x5) +#define FP4_4(x6, x5, x4, x3, x2, x1, x0) \ + F4(x6, x4, x0, x5, x2, x1, x3) + +#define FP5_1(x6, x5, x4, x3, x2, x1, x0) \ + F1(x3, x4, x1, x0, x5, x2, x6) +#define FP5_2(x6, x5, x4, x3, x2, x1, x0) \ + F2(x6, x2, x1, x0, x3, x4, x5) +#define FP5_3(x6, x5, x4, x3, x2, x1, x0) \ + F3(x2, x6, x0, x4, x3, x1, x5) +#define FP5_4(x6, x5, x4, x3, x2, x1, x0) \ + F4(x1, x5, x3, x2, x0, x4, x6) +#define FP5_5(x6, x5, x4, x3, x2, x1, x0) \ + F5(x2, x5, x0, x6, x4, x3, x1) + +/* + * One step, for "n" passes, pass number "p" (1 <= p <= n), using + * input word number "w" and step constant "c". + */ +#define STEP(n, p, x7, x6, x5, x4, x3, x2, x1, x0, w, c) do { \ + sph_u32 t = FP ## n ## _ ## p(x6, x5, x4, x3, x2, x1, x0); \ + (x7) = SPH_T32(SPH_ROTR32(t, 7) + SPH_ROTR32((x7), 11) \ + + (w) + (c)); \ + } while (0) + +/* + * PASSy(n, in) computes pass number "y", for a total of "n", using the + * one-argument macro "in" to access input words. Current state is assumed + * to be held in variables "s0" to "s7". + */ + +#if SPH_SMALL_FOOTPRINT_HAVAL + +#define PASS1(n, in) do { \ + unsigned pass_count; \ + for (pass_count = 0; pass_count < 32; pass_count += 8) { \ + STEP(n, 1, s7, s6, s5, s4, s3, s2, s1, s0, \ + in(pass_count + 0), SPH_C32(0x00000000)); \ + STEP(n, 1, s6, s5, s4, s3, s2, s1, s0, s7, \ + in(pass_count + 1), SPH_C32(0x00000000)); \ + STEP(n, 1, s5, s4, s3, s2, s1, s0, s7, s6, \ + in(pass_count + 2), SPH_C32(0x00000000)); \ + STEP(n, 1, s4, s3, s2, s1, s0, s7, s6, s5, \ + in(pass_count + 3), SPH_C32(0x00000000)); \ + STEP(n, 1, s3, s2, s1, s0, s7, s6, s5, s4, \ + in(pass_count + 4), SPH_C32(0x00000000)); \ + STEP(n, 1, s2, s1, s0, s7, s6, s5, s4, s3, \ + in(pass_count + 5), SPH_C32(0x00000000)); \ + STEP(n, 1, s1, s0, s7, s6, s5, s4, s3, s2, \ + in(pass_count + 6), SPH_C32(0x00000000)); \ + STEP(n, 1, s0, s7, s6, s5, s4, s3, s2, s1, \ + in(pass_count + 7), SPH_C32(0x00000000)); \ + } \ + } while (0) + +#define PASSG(p, n, in) do { \ + unsigned pass_count; \ + for (pass_count = 0; pass_count < 32; pass_count += 8) { \ + STEP(n, p, s7, s6, s5, s4, s3, s2, s1, s0, \ + in(MP ## p[pass_count + 0]), \ + RK ## p[pass_count + 0]); \ + STEP(n, p, s6, s5, s4, s3, s2, s1, s0, s7, \ + in(MP ## p[pass_count + 1]), \ + RK ## p[pass_count + 1]); \ + STEP(n, p, s5, s4, s3, s2, s1, s0, s7, s6, \ + in(MP ## p[pass_count + 2]), \ + RK ## p[pass_count + 2]); \ + STEP(n, p, s4, s3, s2, s1, s0, s7, s6, s5, \ + in(MP ## p[pass_count + 3]), \ + RK ## p[pass_count + 3]); \ + STEP(n, p, s3, s2, s1, s0, s7, s6, s5, s4, \ + in(MP ## p[pass_count + 4]), \ + RK ## p[pass_count + 4]); \ + STEP(n, p, s2, s1, s0, s7, s6, s5, s4, s3, \ + in(MP ## p[pass_count + 5]), \ + RK ## p[pass_count + 5]); \ + STEP(n, p, s1, s0, s7, s6, s5, s4, s3, s2, \ + in(MP ## p[pass_count + 6]), \ + RK ## p[pass_count + 6]); \ + STEP(n, p, s0, s7, s6, s5, s4, s3, s2, s1, \ + in(MP ## p[pass_count + 7]), \ + RK ## p[pass_count + 7]); \ + } \ + } while (0) + +#define PASS2(n, in) PASSG(2, n, in) +#define PASS3(n, in) PASSG(3, n, in) +#define PASS4(n, in) PASSG(4, n, in) +#define PASS5(n, in) PASSG(5, n, in) + +static const unsigned MP2[32] = { + 5, 14, 26, 18, 11, 28, 7, 16, + 0, 23, 20, 22, 1, 10, 4, 8, + 30, 3, 21, 9, 17, 24, 29, 6, + 19, 12, 15, 13, 2, 25, 31, 27 +}; + +static const unsigned MP3[32] = { + 19, 9, 4, 20, 28, 17, 8, 22, + 29, 14, 25, 12, 24, 30, 16, 26, + 31, 15, 7, 3, 1, 0, 18, 27, + 13, 6, 21, 10, 23, 11, 5, 2 +}; + +static const unsigned MP4[32] = { + 24, 4, 0, 14, 2, 7, 28, 23, + 26, 6, 30, 20, 18, 25, 19, 3, + 22, 11, 31, 21, 8, 27, 12, 9, + 1, 29, 5, 15, 17, 10, 16, 13 +}; + +static const unsigned MP5[32] = { + 27, 3, 21, 26, 17, 11, 20, 29, + 19, 0, 12, 7, 13, 8, 31, 10, + 5, 9, 14, 30, 18, 6, 28, 24, + 2, 23, 16, 22, 4, 1, 25, 15 +}; + +static const sph_u32 RK2[32] = { + SPH_C32(0x452821E6), SPH_C32(0x38D01377), + SPH_C32(0xBE5466CF), SPH_C32(0x34E90C6C), + SPH_C32(0xC0AC29B7), SPH_C32(0xC97C50DD), + SPH_C32(0x3F84D5B5), SPH_C32(0xB5470917), + SPH_C32(0x9216D5D9), SPH_C32(0x8979FB1B), + SPH_C32(0xD1310BA6), SPH_C32(0x98DFB5AC), + SPH_C32(0x2FFD72DB), SPH_C32(0xD01ADFB7), + SPH_C32(0xB8E1AFED), SPH_C32(0x6A267E96), + SPH_C32(0xBA7C9045), SPH_C32(0xF12C7F99), + SPH_C32(0x24A19947), SPH_C32(0xB3916CF7), + SPH_C32(0x0801F2E2), SPH_C32(0x858EFC16), + SPH_C32(0x636920D8), SPH_C32(0x71574E69), + SPH_C32(0xA458FEA3), SPH_C32(0xF4933D7E), + SPH_C32(0x0D95748F), SPH_C32(0x728EB658), + SPH_C32(0x718BCD58), SPH_C32(0x82154AEE), + SPH_C32(0x7B54A41D), SPH_C32(0xC25A59B5) +}; + +static const sph_u32 RK3[32] = { + SPH_C32(0x9C30D539), SPH_C32(0x2AF26013), + SPH_C32(0xC5D1B023), SPH_C32(0x286085F0), + SPH_C32(0xCA417918), SPH_C32(0xB8DB38EF), + SPH_C32(0x8E79DCB0), SPH_C32(0x603A180E), + SPH_C32(0x6C9E0E8B), SPH_C32(0xB01E8A3E), + SPH_C32(0xD71577C1), SPH_C32(0xBD314B27), + SPH_C32(0x78AF2FDA), SPH_C32(0x55605C60), + SPH_C32(0xE65525F3), SPH_C32(0xAA55AB94), + SPH_C32(0x57489862), SPH_C32(0x63E81440), + SPH_C32(0x55CA396A), SPH_C32(0x2AAB10B6), + SPH_C32(0xB4CC5C34), SPH_C32(0x1141E8CE), + SPH_C32(0xA15486AF), SPH_C32(0x7C72E993), + SPH_C32(0xB3EE1411), SPH_C32(0x636FBC2A), + SPH_C32(0x2BA9C55D), SPH_C32(0x741831F6), + SPH_C32(0xCE5C3E16), SPH_C32(0x9B87931E), + SPH_C32(0xAFD6BA33), SPH_C32(0x6C24CF5C) +}; + +static const sph_u32 RK4[32] = { + SPH_C32(0x7A325381), SPH_C32(0x28958677), + SPH_C32(0x3B8F4898), SPH_C32(0x6B4BB9AF), + SPH_C32(0xC4BFE81B), SPH_C32(0x66282193), + SPH_C32(0x61D809CC), SPH_C32(0xFB21A991), + SPH_C32(0x487CAC60), SPH_C32(0x5DEC8032), + SPH_C32(0xEF845D5D), SPH_C32(0xE98575B1), + SPH_C32(0xDC262302), SPH_C32(0xEB651B88), + SPH_C32(0x23893E81), SPH_C32(0xD396ACC5), + SPH_C32(0x0F6D6FF3), SPH_C32(0x83F44239), + SPH_C32(0x2E0B4482), SPH_C32(0xA4842004), + SPH_C32(0x69C8F04A), SPH_C32(0x9E1F9B5E), + SPH_C32(0x21C66842), SPH_C32(0xF6E96C9A), + SPH_C32(0x670C9C61), SPH_C32(0xABD388F0), + SPH_C32(0x6A51A0D2), SPH_C32(0xD8542F68), + SPH_C32(0x960FA728), SPH_C32(0xAB5133A3), + SPH_C32(0x6EEF0B6C), SPH_C32(0x137A3BE4) +}; + +static const sph_u32 RK5[32] = { + SPH_C32(0xBA3BF050), SPH_C32(0x7EFB2A98), + SPH_C32(0xA1F1651D), SPH_C32(0x39AF0176), + SPH_C32(0x66CA593E), SPH_C32(0x82430E88), + SPH_C32(0x8CEE8619), SPH_C32(0x456F9FB4), + SPH_C32(0x7D84A5C3), SPH_C32(0x3B8B5EBE), + SPH_C32(0xE06F75D8), SPH_C32(0x85C12073), + SPH_C32(0x401A449F), SPH_C32(0x56C16AA6), + SPH_C32(0x4ED3AA62), SPH_C32(0x363F7706), + SPH_C32(0x1BFEDF72), SPH_C32(0x429B023D), + SPH_C32(0x37D0D724), SPH_C32(0xD00A1248), + SPH_C32(0xDB0FEAD3), SPH_C32(0x49F1C09B), + SPH_C32(0x075372C9), SPH_C32(0x80991B7B), + SPH_C32(0x25D479D8), SPH_C32(0xF6E8DEF7), + SPH_C32(0xE3FE501A), SPH_C32(0xB6794C3B), + SPH_C32(0x976CE0BD), SPH_C32(0x04C006BA), + SPH_C32(0xC1A94FB6), SPH_C32(0x409F60C4) +}; + +#else + +#define PASS1(n, in) do { \ + STEP(n, 1, s7, s6, s5, s4, s3, s2, s1, s0, in( 0), SPH_C32(0x00000000)); \ + STEP(n, 1, s6, s5, s4, s3, s2, s1, s0, s7, in( 1), SPH_C32(0x00000000)); \ + STEP(n, 1, s5, s4, s3, s2, s1, s0, s7, s6, in( 2), SPH_C32(0x00000000)); \ + STEP(n, 1, s4, s3, s2, s1, s0, s7, s6, s5, in( 3), SPH_C32(0x00000000)); \ + STEP(n, 1, s3, s2, s1, s0, s7, s6, s5, s4, in( 4), SPH_C32(0x00000000)); \ + STEP(n, 1, s2, s1, s0, s7, s6, s5, s4, s3, in( 5), SPH_C32(0x00000000)); \ + STEP(n, 1, s1, s0, s7, s6, s5, s4, s3, s2, in( 6), SPH_C32(0x00000000)); \ + STEP(n, 1, s0, s7, s6, s5, s4, s3, s2, s1, in( 7), SPH_C32(0x00000000)); \ + \ + STEP(n, 1, s7, s6, s5, s4, s3, s2, s1, s0, in( 8), SPH_C32(0x00000000)); \ + STEP(n, 1, s6, s5, s4, s3, s2, s1, s0, s7, in( 9), SPH_C32(0x00000000)); \ + STEP(n, 1, s5, s4, s3, s2, s1, s0, s7, s6, in(10), SPH_C32(0x00000000)); \ + STEP(n, 1, s4, s3, s2, s1, s0, s7, s6, s5, in(11), SPH_C32(0x00000000)); \ + STEP(n, 1, s3, s2, s1, s0, s7, s6, s5, s4, in(12), SPH_C32(0x00000000)); \ + STEP(n, 1, s2, s1, s0, s7, s6, s5, s4, s3, in(13), SPH_C32(0x00000000)); \ + STEP(n, 1, s1, s0, s7, s6, s5, s4, s3, s2, in(14), SPH_C32(0x00000000)); \ + STEP(n, 1, s0, s7, s6, s5, s4, s3, s2, s1, in(15), SPH_C32(0x00000000)); \ + \ + STEP(n, 1, s7, s6, s5, s4, s3, s2, s1, s0, in(16), SPH_C32(0x00000000)); \ + STEP(n, 1, s6, s5, s4, s3, s2, s1, s0, s7, in(17), SPH_C32(0x00000000)); \ + STEP(n, 1, s5, s4, s3, s2, s1, s0, s7, s6, in(18), SPH_C32(0x00000000)); \ + STEP(n, 1, s4, s3, s2, s1, s0, s7, s6, s5, in(19), SPH_C32(0x00000000)); \ + STEP(n, 1, s3, s2, s1, s0, s7, s6, s5, s4, in(20), SPH_C32(0x00000000)); \ + STEP(n, 1, s2, s1, s0, s7, s6, s5, s4, s3, in(21), SPH_C32(0x00000000)); \ + STEP(n, 1, s1, s0, s7, s6, s5, s4, s3, s2, in(22), SPH_C32(0x00000000)); \ + STEP(n, 1, s0, s7, s6, s5, s4, s3, s2, s1, in(23), SPH_C32(0x00000000)); \ + \ + STEP(n, 1, s7, s6, s5, s4, s3, s2, s1, s0, in(24), SPH_C32(0x00000000)); \ + STEP(n, 1, s6, s5, s4, s3, s2, s1, s0, s7, in(25), SPH_C32(0x00000000)); \ + STEP(n, 1, s5, s4, s3, s2, s1, s0, s7, s6, in(26), SPH_C32(0x00000000)); \ + STEP(n, 1, s4, s3, s2, s1, s0, s7, s6, s5, in(27), SPH_C32(0x00000000)); \ + STEP(n, 1, s3, s2, s1, s0, s7, s6, s5, s4, in(28), SPH_C32(0x00000000)); \ + STEP(n, 1, s2, s1, s0, s7, s6, s5, s4, s3, in(29), SPH_C32(0x00000000)); \ + STEP(n, 1, s1, s0, s7, s6, s5, s4, s3, s2, in(30), SPH_C32(0x00000000)); \ + STEP(n, 1, s0, s7, s6, s5, s4, s3, s2, s1, in(31), SPH_C32(0x00000000)); \ + } while (0) + +#define PASS2(n, in) do { \ + STEP(n, 2, s7, s6, s5, s4, s3, s2, s1, s0, in( 5), SPH_C32(0x452821E6)); \ + STEP(n, 2, s6, s5, s4, s3, s2, s1, s0, s7, in(14), SPH_C32(0x38D01377)); \ + STEP(n, 2, s5, s4, s3, s2, s1, s0, s7, s6, in(26), SPH_C32(0xBE5466CF)); \ + STEP(n, 2, s4, s3, s2, s1, s0, s7, s6, s5, in(18), SPH_C32(0x34E90C6C)); \ + STEP(n, 2, s3, s2, s1, s0, s7, s6, s5, s4, in(11), SPH_C32(0xC0AC29B7)); \ + STEP(n, 2, s2, s1, s0, s7, s6, s5, s4, s3, in(28), SPH_C32(0xC97C50DD)); \ + STEP(n, 2, s1, s0, s7, s6, s5, s4, s3, s2, in( 7), SPH_C32(0x3F84D5B5)); \ + STEP(n, 2, s0, s7, s6, s5, s4, s3, s2, s1, in(16), SPH_C32(0xB5470917)); \ + \ + STEP(n, 2, s7, s6, s5, s4, s3, s2, s1, s0, in( 0), SPH_C32(0x9216D5D9)); \ + STEP(n, 2, s6, s5, s4, s3, s2, s1, s0, s7, in(23), SPH_C32(0x8979FB1B)); \ + STEP(n, 2, s5, s4, s3, s2, s1, s0, s7, s6, in(20), SPH_C32(0xD1310BA6)); \ + STEP(n, 2, s4, s3, s2, s1, s0, s7, s6, s5, in(22), SPH_C32(0x98DFB5AC)); \ + STEP(n, 2, s3, s2, s1, s0, s7, s6, s5, s4, in( 1), SPH_C32(0x2FFD72DB)); \ + STEP(n, 2, s2, s1, s0, s7, s6, s5, s4, s3, in(10), SPH_C32(0xD01ADFB7)); \ + STEP(n, 2, s1, s0, s7, s6, s5, s4, s3, s2, in( 4), SPH_C32(0xB8E1AFED)); \ + STEP(n, 2, s0, s7, s6, s5, s4, s3, s2, s1, in( 8), SPH_C32(0x6A267E96)); \ + \ + STEP(n, 2, s7, s6, s5, s4, s3, s2, s1, s0, in(30), SPH_C32(0xBA7C9045)); \ + STEP(n, 2, s6, s5, s4, s3, s2, s1, s0, s7, in( 3), SPH_C32(0xF12C7F99)); \ + STEP(n, 2, s5, s4, s3, s2, s1, s0, s7, s6, in(21), SPH_C32(0x24A19947)); \ + STEP(n, 2, s4, s3, s2, s1, s0, s7, s6, s5, in( 9), SPH_C32(0xB3916CF7)); \ + STEP(n, 2, s3, s2, s1, s0, s7, s6, s5, s4, in(17), SPH_C32(0x0801F2E2)); \ + STEP(n, 2, s2, s1, s0, s7, s6, s5, s4, s3, in(24), SPH_C32(0x858EFC16)); \ + STEP(n, 2, s1, s0, s7, s6, s5, s4, s3, s2, in(29), SPH_C32(0x636920D8)); \ + STEP(n, 2, s0, s7, s6, s5, s4, s3, s2, s1, in( 6), SPH_C32(0x71574E69)); \ + \ + STEP(n, 2, s7, s6, s5, s4, s3, s2, s1, s0, in(19), SPH_C32(0xA458FEA3)); \ + STEP(n, 2, s6, s5, s4, s3, s2, s1, s0, s7, in(12), SPH_C32(0xF4933D7E)); \ + STEP(n, 2, s5, s4, s3, s2, s1, s0, s7, s6, in(15), SPH_C32(0x0D95748F)); \ + STEP(n, 2, s4, s3, s2, s1, s0, s7, s6, s5, in(13), SPH_C32(0x728EB658)); \ + STEP(n, 2, s3, s2, s1, s0, s7, s6, s5, s4, in( 2), SPH_C32(0x718BCD58)); \ + STEP(n, 2, s2, s1, s0, s7, s6, s5, s4, s3, in(25), SPH_C32(0x82154AEE)); \ + STEP(n, 2, s1, s0, s7, s6, s5, s4, s3, s2, in(31), SPH_C32(0x7B54A41D)); \ + STEP(n, 2, s0, s7, s6, s5, s4, s3, s2, s1, in(27), SPH_C32(0xC25A59B5)); \ + } while (0) + +#define PASS3(n, in) do { \ + STEP(n, 3, s7, s6, s5, s4, s3, s2, s1, s0, in(19), SPH_C32(0x9C30D539)); \ + STEP(n, 3, s6, s5, s4, s3, s2, s1, s0, s7, in( 9), SPH_C32(0x2AF26013)); \ + STEP(n, 3, s5, s4, s3, s2, s1, s0, s7, s6, in( 4), SPH_C32(0xC5D1B023)); \ + STEP(n, 3, s4, s3, s2, s1, s0, s7, s6, s5, in(20), SPH_C32(0x286085F0)); \ + STEP(n, 3, s3, s2, s1, s0, s7, s6, s5, s4, in(28), SPH_C32(0xCA417918)); \ + STEP(n, 3, s2, s1, s0, s7, s6, s5, s4, s3, in(17), SPH_C32(0xB8DB38EF)); \ + STEP(n, 3, s1, s0, s7, s6, s5, s4, s3, s2, in( 8), SPH_C32(0x8E79DCB0)); \ + STEP(n, 3, s0, s7, s6, s5, s4, s3, s2, s1, in(22), SPH_C32(0x603A180E)); \ + \ + STEP(n, 3, s7, s6, s5, s4, s3, s2, s1, s0, in(29), SPH_C32(0x6C9E0E8B)); \ + STEP(n, 3, s6, s5, s4, s3, s2, s1, s0, s7, in(14), SPH_C32(0xB01E8A3E)); \ + STEP(n, 3, s5, s4, s3, s2, s1, s0, s7, s6, in(25), SPH_C32(0xD71577C1)); \ + STEP(n, 3, s4, s3, s2, s1, s0, s7, s6, s5, in(12), SPH_C32(0xBD314B27)); \ + STEP(n, 3, s3, s2, s1, s0, s7, s6, s5, s4, in(24), SPH_C32(0x78AF2FDA)); \ + STEP(n, 3, s2, s1, s0, s7, s6, s5, s4, s3, in(30), SPH_C32(0x55605C60)); \ + STEP(n, 3, s1, s0, s7, s6, s5, s4, s3, s2, in(16), SPH_C32(0xE65525F3)); \ + STEP(n, 3, s0, s7, s6, s5, s4, s3, s2, s1, in(26), SPH_C32(0xAA55AB94)); \ + \ + STEP(n, 3, s7, s6, s5, s4, s3, s2, s1, s0, in(31), SPH_C32(0x57489862)); \ + STEP(n, 3, s6, s5, s4, s3, s2, s1, s0, s7, in(15), SPH_C32(0x63E81440)); \ + STEP(n, 3, s5, s4, s3, s2, s1, s0, s7, s6, in( 7), SPH_C32(0x55CA396A)); \ + STEP(n, 3, s4, s3, s2, s1, s0, s7, s6, s5, in( 3), SPH_C32(0x2AAB10B6)); \ + STEP(n, 3, s3, s2, s1, s0, s7, s6, s5, s4, in( 1), SPH_C32(0xB4CC5C34)); \ + STEP(n, 3, s2, s1, s0, s7, s6, s5, s4, s3, in( 0), SPH_C32(0x1141E8CE)); \ + STEP(n, 3, s1, s0, s7, s6, s5, s4, s3, s2, in(18), SPH_C32(0xA15486AF)); \ + STEP(n, 3, s0, s7, s6, s5, s4, s3, s2, s1, in(27), SPH_C32(0x7C72E993)); \ + \ + STEP(n, 3, s7, s6, s5, s4, s3, s2, s1, s0, in(13), SPH_C32(0xB3EE1411)); \ + STEP(n, 3, s6, s5, s4, s3, s2, s1, s0, s7, in( 6), SPH_C32(0x636FBC2A)); \ + STEP(n, 3, s5, s4, s3, s2, s1, s0, s7, s6, in(21), SPH_C32(0x2BA9C55D)); \ + STEP(n, 3, s4, s3, s2, s1, s0, s7, s6, s5, in(10), SPH_C32(0x741831F6)); \ + STEP(n, 3, s3, s2, s1, s0, s7, s6, s5, s4, in(23), SPH_C32(0xCE5C3E16)); \ + STEP(n, 3, s2, s1, s0, s7, s6, s5, s4, s3, in(11), SPH_C32(0x9B87931E)); \ + STEP(n, 3, s1, s0, s7, s6, s5, s4, s3, s2, in( 5), SPH_C32(0xAFD6BA33)); \ + STEP(n, 3, s0, s7, s6, s5, s4, s3, s2, s1, in( 2), SPH_C32(0x6C24CF5C)); \ + } while (0) + +#define PASS4(n, in) do { \ + STEP(n, 4, s7, s6, s5, s4, s3, s2, s1, s0, in(24), SPH_C32(0x7A325381)); \ + STEP(n, 4, s6, s5, s4, s3, s2, s1, s0, s7, in( 4), SPH_C32(0x28958677)); \ + STEP(n, 4, s5, s4, s3, s2, s1, s0, s7, s6, in( 0), SPH_C32(0x3B8F4898)); \ + STEP(n, 4, s4, s3, s2, s1, s0, s7, s6, s5, in(14), SPH_C32(0x6B4BB9AF)); \ + STEP(n, 4, s3, s2, s1, s0, s7, s6, s5, s4, in( 2), SPH_C32(0xC4BFE81B)); \ + STEP(n, 4, s2, s1, s0, s7, s6, s5, s4, s3, in( 7), SPH_C32(0x66282193)); \ + STEP(n, 4, s1, s0, s7, s6, s5, s4, s3, s2, in(28), SPH_C32(0x61D809CC)); \ + STEP(n, 4, s0, s7, s6, s5, s4, s3, s2, s1, in(23), SPH_C32(0xFB21A991)); \ + \ + STEP(n, 4, s7, s6, s5, s4, s3, s2, s1, s0, in(26), SPH_C32(0x487CAC60)); \ + STEP(n, 4, s6, s5, s4, s3, s2, s1, s0, s7, in( 6), SPH_C32(0x5DEC8032)); \ + STEP(n, 4, s5, s4, s3, s2, s1, s0, s7, s6, in(30), SPH_C32(0xEF845D5D)); \ + STEP(n, 4, s4, s3, s2, s1, s0, s7, s6, s5, in(20), SPH_C32(0xE98575B1)); \ + STEP(n, 4, s3, s2, s1, s0, s7, s6, s5, s4, in(18), SPH_C32(0xDC262302)); \ + STEP(n, 4, s2, s1, s0, s7, s6, s5, s4, s3, in(25), SPH_C32(0xEB651B88)); \ + STEP(n, 4, s1, s0, s7, s6, s5, s4, s3, s2, in(19), SPH_C32(0x23893E81)); \ + STEP(n, 4, s0, s7, s6, s5, s4, s3, s2, s1, in( 3), SPH_C32(0xD396ACC5)); \ + \ + STEP(n, 4, s7, s6, s5, s4, s3, s2, s1, s0, in(22), SPH_C32(0x0F6D6FF3)); \ + STEP(n, 4, s6, s5, s4, s3, s2, s1, s0, s7, in(11), SPH_C32(0x83F44239)); \ + STEP(n, 4, s5, s4, s3, s2, s1, s0, s7, s6, in(31), SPH_C32(0x2E0B4482)); \ + STEP(n, 4, s4, s3, s2, s1, s0, s7, s6, s5, in(21), SPH_C32(0xA4842004)); \ + STEP(n, 4, s3, s2, s1, s0, s7, s6, s5, s4, in( 8), SPH_C32(0x69C8F04A)); \ + STEP(n, 4, s2, s1, s0, s7, s6, s5, s4, s3, in(27), SPH_C32(0x9E1F9B5E)); \ + STEP(n, 4, s1, s0, s7, s6, s5, s4, s3, s2, in(12), SPH_C32(0x21C66842)); \ + STEP(n, 4, s0, s7, s6, s5, s4, s3, s2, s1, in( 9), SPH_C32(0xF6E96C9A)); \ + \ + STEP(n, 4, s7, s6, s5, s4, s3, s2, s1, s0, in( 1), SPH_C32(0x670C9C61)); \ + STEP(n, 4, s6, s5, s4, s3, s2, s1, s0, s7, in(29), SPH_C32(0xABD388F0)); \ + STEP(n, 4, s5, s4, s3, s2, s1, s0, s7, s6, in( 5), SPH_C32(0x6A51A0D2)); \ + STEP(n, 4, s4, s3, s2, s1, s0, s7, s6, s5, in(15), SPH_C32(0xD8542F68)); \ + STEP(n, 4, s3, s2, s1, s0, s7, s6, s5, s4, in(17), SPH_C32(0x960FA728)); \ + STEP(n, 4, s2, s1, s0, s7, s6, s5, s4, s3, in(10), SPH_C32(0xAB5133A3)); \ + STEP(n, 4, s1, s0, s7, s6, s5, s4, s3, s2, in(16), SPH_C32(0x6EEF0B6C)); \ + STEP(n, 4, s0, s7, s6, s5, s4, s3, s2, s1, in(13), SPH_C32(0x137A3BE4)); \ + } while (0) + +#define PASS5(n, in) do { \ + STEP(n, 5, s7, s6, s5, s4, s3, s2, s1, s0, in(27), SPH_C32(0xBA3BF050)); \ + STEP(n, 5, s6, s5, s4, s3, s2, s1, s0, s7, in( 3), SPH_C32(0x7EFB2A98)); \ + STEP(n, 5, s5, s4, s3, s2, s1, s0, s7, s6, in(21), SPH_C32(0xA1F1651D)); \ + STEP(n, 5, s4, s3, s2, s1, s0, s7, s6, s5, in(26), SPH_C32(0x39AF0176)); \ + STEP(n, 5, s3, s2, s1, s0, s7, s6, s5, s4, in(17), SPH_C32(0x66CA593E)); \ + STEP(n, 5, s2, s1, s0, s7, s6, s5, s4, s3, in(11), SPH_C32(0x82430E88)); \ + STEP(n, 5, s1, s0, s7, s6, s5, s4, s3, s2, in(20), SPH_C32(0x8CEE8619)); \ + STEP(n, 5, s0, s7, s6, s5, s4, s3, s2, s1, in(29), SPH_C32(0x456F9FB4)); \ + \ + STEP(n, 5, s7, s6, s5, s4, s3, s2, s1, s0, in(19), SPH_C32(0x7D84A5C3)); \ + STEP(n, 5, s6, s5, s4, s3, s2, s1, s0, s7, in( 0), SPH_C32(0x3B8B5EBE)); \ + STEP(n, 5, s5, s4, s3, s2, s1, s0, s7, s6, in(12), SPH_C32(0xE06F75D8)); \ + STEP(n, 5, s4, s3, s2, s1, s0, s7, s6, s5, in( 7), SPH_C32(0x85C12073)); \ + STEP(n, 5, s3, s2, s1, s0, s7, s6, s5, s4, in(13), SPH_C32(0x401A449F)); \ + STEP(n, 5, s2, s1, s0, s7, s6, s5, s4, s3, in( 8), SPH_C32(0x56C16AA6)); \ + STEP(n, 5, s1, s0, s7, s6, s5, s4, s3, s2, in(31), SPH_C32(0x4ED3AA62)); \ + STEP(n, 5, s0, s7, s6, s5, s4, s3, s2, s1, in(10), SPH_C32(0x363F7706)); \ + \ + STEP(n, 5, s7, s6, s5, s4, s3, s2, s1, s0, in( 5), SPH_C32(0x1BFEDF72)); \ + STEP(n, 5, s6, s5, s4, s3, s2, s1, s0, s7, in( 9), SPH_C32(0x429B023D)); \ + STEP(n, 5, s5, s4, s3, s2, s1, s0, s7, s6, in(14), SPH_C32(0x37D0D724)); \ + STEP(n, 5, s4, s3, s2, s1, s0, s7, s6, s5, in(30), SPH_C32(0xD00A1248)); \ + STEP(n, 5, s3, s2, s1, s0, s7, s6, s5, s4, in(18), SPH_C32(0xDB0FEAD3)); \ + STEP(n, 5, s2, s1, s0, s7, s6, s5, s4, s3, in( 6), SPH_C32(0x49F1C09B)); \ + STEP(n, 5, s1, s0, s7, s6, s5, s4, s3, s2, in(28), SPH_C32(0x075372C9)); \ + STEP(n, 5, s0, s7, s6, s5, s4, s3, s2, s1, in(24), SPH_C32(0x80991B7B)); \ + \ + STEP(n, 5, s7, s6, s5, s4, s3, s2, s1, s0, in( 2), SPH_C32(0x25D479D8)); \ + STEP(n, 5, s6, s5, s4, s3, s2, s1, s0, s7, in(23), SPH_C32(0xF6E8DEF7)); \ + STEP(n, 5, s5, s4, s3, s2, s1, s0, s7, s6, in(16), SPH_C32(0xE3FE501A)); \ + STEP(n, 5, s4, s3, s2, s1, s0, s7, s6, s5, in(22), SPH_C32(0xB6794C3B)); \ + STEP(n, 5, s3, s2, s1, s0, s7, s6, s5, s4, in( 4), SPH_C32(0x976CE0BD)); \ + STEP(n, 5, s2, s1, s0, s7, s6, s5, s4, s3, in( 1), SPH_C32(0x04C006BA)); \ + STEP(n, 5, s1, s0, s7, s6, s5, s4, s3, s2, in(25), SPH_C32(0xC1A94FB6)); \ + STEP(n, 5, s0, s7, s6, s5, s4, s3, s2, s1, in(15), SPH_C32(0x409F60C4)); \ + } while (0) + +#endif + +#define SAVE_STATE \ + sph_u32 u0, u1, u2, u3, u4, u5, u6, u7; \ + do { \ + u0 = s0; \ + u1 = s1; \ + u2 = s2; \ + u3 = s3; \ + u4 = s4; \ + u5 = s5; \ + u6 = s6; \ + u7 = s7; \ + } while (0) + +#define UPDATE_STATE do { \ + s0 = SPH_T32(s0 + u0); \ + s1 = SPH_T32(s1 + u1); \ + s2 = SPH_T32(s2 + u2); \ + s3 = SPH_T32(s3 + u3); \ + s4 = SPH_T32(s4 + u4); \ + s5 = SPH_T32(s5 + u5); \ + s6 = SPH_T32(s6 + u6); \ + s7 = SPH_T32(s7 + u7); \ + } while (0) + +/* + * COREn(in) performs the core HAVAL computation for "n" passes, using + * the one-argument macro "in" to access the input words. Running state + * is held in variable "s0" to "s7". + */ + +#define CORE3(in) do { \ + SAVE_STATE; \ + PASS1(3, in); \ + PASS2(3, in); \ + PASS3(3, in); \ + UPDATE_STATE; \ + } while (0) + +#define CORE4(in) do { \ + SAVE_STATE; \ + PASS1(4, in); \ + PASS2(4, in); \ + PASS3(4, in); \ + PASS4(4, in); \ + UPDATE_STATE; \ + } while (0) + +#define CORE5(in) do { \ + SAVE_STATE; \ + PASS1(5, in); \ + PASS2(5, in); \ + PASS3(5, in); \ + PASS4(5, in); \ + PASS5(5, in); \ + UPDATE_STATE; \ + } while (0) + +/* + * DSTATE declares the state variables "s0" to "s7". + */ +#define DSTATE sph_u32 s0, s1, s2, s3, s4, s5, s6, s7 + +/* + * RSTATE fills the state variables from the context "sc". + */ +#define RSTATE do { \ + s0 = sc->s0; \ + s1 = sc->s1; \ + s2 = sc->s2; \ + s3 = sc->s3; \ + s4 = sc->s4; \ + s5 = sc->s5; \ + s6 = sc->s6; \ + s7 = sc->s7; \ + } while (0) + +/* + * WSTATE updates the context "sc" from the state variables. + */ +#define WSTATE do { \ + sc->s0 = s0; \ + sc->s1 = s1; \ + sc->s2 = s2; \ + sc->s3 = s3; \ + sc->s4 = s4; \ + sc->s5 = s5; \ + sc->s6 = s6; \ + sc->s7 = s7; \ + } while (0) + +/* + * Initialize a context. "olen" is the output length, in 32-bit words + * (between 4 and 8, inclusive). "passes" is the number of passes + * (3, 4 or 5). + */ +static void +haval_init(sph_haval_context *sc, unsigned olen, unsigned passes) +{ + sc->s0 = SPH_C32(0x243F6A88); + sc->s1 = SPH_C32(0x85A308D3); + sc->s2 = SPH_C32(0x13198A2E); + sc->s3 = SPH_C32(0x03707344); + sc->s4 = SPH_C32(0xA4093822); + sc->s5 = SPH_C32(0x299F31D0); + sc->s6 = SPH_C32(0x082EFA98); + sc->s7 = SPH_C32(0xEC4E6C89); + sc->olen = olen; + sc->passes = passes; +#if SPH_64 + sc->count = 0; +#else + sc->count_high = 0; + sc->count_low = 0; +#endif +} + +/* + * IN_PREPARE(data) contains declarations and code to prepare for + * reading input words pointed to by "data". + * INW(i) reads the word number "i" (from 0 to 31). + */ +#if SPH_LITTLE_FAST +#define IN_PREPARE(indata) const unsigned char *const load_ptr = \ + (const unsigned char *)(indata) +#define INW(i) sph_dec32le_aligned(load_ptr + 4 * (i)) +#else +#define IN_PREPARE(indata) \ + sph_u32 X_var[32]; \ + int load_index; \ + \ + for (load_index = 0; load_index < 32; load_index ++) \ + X_var[load_index] = sph_dec32le_aligned( \ + (const unsigned char *)(indata) + 4 * load_index) +#define INW(i) X_var[i] +#endif + +/* + * Mixing operation used for 128-bit output tailoring. This function + * takes the byte 0 from a0, byte 1 from a1, byte 2 from a2 and byte 3 + * from a3, and combines them into a 32-bit word, which is then rotated + * to the left by n bits. + */ +static SPH_INLINE sph_u32 +mix128(sph_u32 a0, sph_u32 a1, sph_u32 a2, sph_u32 a3, int n) +{ + sph_u32 tmp; + + tmp = (a0 & SPH_C32(0x000000FF)) + | (a1 & SPH_C32(0x0000FF00)) + | (a2 & SPH_C32(0x00FF0000)) + | (a3 & SPH_C32(0xFF000000)); + if (n > 0) + tmp = SPH_ROTL32(tmp, n); + return tmp; +} + +/* + * Mixing operation used to compute output word 0 for 160-bit output. + */ +static SPH_INLINE sph_u32 +mix160_0(sph_u32 x5, sph_u32 x6, sph_u32 x7) +{ + sph_u32 tmp; + + tmp = (x5 & SPH_C32(0x01F80000)) + | (x6 & SPH_C32(0xFE000000)) + | (x7 & SPH_C32(0x0000003F)); + return SPH_ROTL32(tmp, 13); +} + +/* + * Mixing operation used to compute output word 1 for 160-bit output. + */ +static SPH_INLINE sph_u32 +mix160_1(sph_u32 x5, sph_u32 x6, sph_u32 x7) +{ + sph_u32 tmp; + + tmp = (x5 & SPH_C32(0xFE000000)) + | (x6 & SPH_C32(0x0000003F)) + | (x7 & SPH_C32(0x00000FC0)); + return SPH_ROTL32(tmp, 7); +} + +/* + * Mixing operation used to compute output word 2 for 160-bit output. + */ +static SPH_INLINE sph_u32 +mix160_2(sph_u32 x5, sph_u32 x6, sph_u32 x7) +{ + sph_u32 tmp; + + tmp = (x5 & SPH_C32(0x0000003F)) + | (x6 & SPH_C32(0x00000FC0)) + | (x7 & SPH_C32(0x0007F000)); + return tmp; +} + +/* + * Mixing operation used to compute output word 3 for 160-bit output. + */ +static SPH_INLINE sph_u32 +mix160_3(sph_u32 x5, sph_u32 x6, sph_u32 x7) +{ + sph_u32 tmp; + + tmp = (x5 & SPH_C32(0x00000FC0)) + | (x6 & SPH_C32(0x0007F000)) + | (x7 & SPH_C32(0x01F80000)); + return tmp >> 6; +} + +/* + * Mixing operation used to compute output word 4 for 160-bit output. + */ +static SPH_INLINE sph_u32 +mix160_4(sph_u32 x5, sph_u32 x6, sph_u32 x7) +{ + sph_u32 tmp; + + tmp = (x5 & SPH_C32(0x0007F000)) + | (x6 & SPH_C32(0x01F80000)) + | (x7 & SPH_C32(0xFE000000)); + return tmp >> 12; +} + +/* + * Mixing operation used to compute output word 0 for 192-bit output. + */ +static SPH_INLINE sph_u32 +mix192_0(sph_u32 x6, sph_u32 x7) +{ + sph_u32 tmp; + + tmp = (x6 & SPH_C32(0xFC000000)) | (x7 & SPH_C32(0x0000001F)); + return SPH_ROTL32(tmp, 6); +} + +/* + * Mixing operation used to compute output word 1 for 192-bit output. + */ +static SPH_INLINE sph_u32 +mix192_1(sph_u32 x6, sph_u32 x7) +{ + return (x6 & SPH_C32(0x0000001F)) | (x7 & SPH_C32(0x000003E0)); +} + +/* + * Mixing operation used to compute output word 2 for 192-bit output. + */ +static SPH_INLINE sph_u32 +mix192_2(sph_u32 x6, sph_u32 x7) +{ + return ((x6 & SPH_C32(0x000003E0)) | (x7 & SPH_C32(0x0000FC00))) >> 5; +} + +/* + * Mixing operation used to compute output word 3 for 192-bit output. + */ +static SPH_INLINE sph_u32 +mix192_3(sph_u32 x6, sph_u32 x7) +{ + return ((x6 & SPH_C32(0x0000FC00)) | (x7 & SPH_C32(0x001F0000))) >> 10; +} + +/* + * Mixing operation used to compute output word 4 for 192-bit output. + */ +static SPH_INLINE sph_u32 +mix192_4(sph_u32 x6, sph_u32 x7) +{ + return ((x6 & SPH_C32(0x001F0000)) | (x7 & SPH_C32(0x03E00000))) >> 16; +} + +/* + * Mixing operation used to compute output word 5 for 192-bit output. + */ +static SPH_INLINE sph_u32 +mix192_5(sph_u32 x6, sph_u32 x7) +{ + return ((x6 & SPH_C32(0x03E00000)) | (x7 & SPH_C32(0xFC000000))) >> 21; +} + +/* + * Write out HAVAL output. The output length is tailored to the requested + * length. + */ +static void +haval_out(sph_haval_context *sc, void *dst) +{ + DSTATE; + unsigned char *buf; + + buf = (unsigned char*)dst; + RSTATE; + switch (sc->olen) { + case 4: + sph_enc32le(buf, SPH_T32(s0 + mix128(s7, s4, s5, s6, 24))); + sph_enc32le(buf + 4, SPH_T32(s1 + mix128(s6, s7, s4, s5, 16))); + sph_enc32le(buf + 8, SPH_T32(s2 + mix128(s5, s6, s7, s4, 8))); + sph_enc32le(buf + 12, SPH_T32(s3 + mix128(s4, s5, s6, s7, 0))); + break; + case 5: + sph_enc32le(buf, SPH_T32(s0 + mix160_0(s5, s6, s7))); + sph_enc32le(buf + 4, SPH_T32(s1 + mix160_1(s5, s6, s7))); + sph_enc32le(buf + 8, SPH_T32(s2 + mix160_2(s5, s6, s7))); + sph_enc32le(buf + 12, SPH_T32(s3 + mix160_3(s5, s6, s7))); + sph_enc32le(buf + 16, SPH_T32(s4 + mix160_4(s5, s6, s7))); + break; + case 6: + sph_enc32le(buf, SPH_T32(s0 + mix192_0(s6, s7))); + sph_enc32le(buf + 4, SPH_T32(s1 + mix192_1(s6, s7))); + sph_enc32le(buf + 8, SPH_T32(s2 + mix192_2(s6, s7))); + sph_enc32le(buf + 12, SPH_T32(s3 + mix192_3(s6, s7))); + sph_enc32le(buf + 16, SPH_T32(s4 + mix192_4(s6, s7))); + sph_enc32le(buf + 20, SPH_T32(s5 + mix192_5(s6, s7))); + break; + case 7: + sph_enc32le(buf, SPH_T32(s0 + ((s7 >> 27) & 0x1F))); + sph_enc32le(buf + 4, SPH_T32(s1 + ((s7 >> 22) & 0x1F))); + sph_enc32le(buf + 8, SPH_T32(s2 + ((s7 >> 18) & 0x0F))); + sph_enc32le(buf + 12, SPH_T32(s3 + ((s7 >> 13) & 0x1F))); + sph_enc32le(buf + 16, SPH_T32(s4 + ((s7 >> 9) & 0x0F))); + sph_enc32le(buf + 20, SPH_T32(s5 + ((s7 >> 4) & 0x1F))); + sph_enc32le(buf + 24, SPH_T32(s6 + ((s7 ) & 0x0F))); + break; + case 8: + sph_enc32le(buf, s0); + sph_enc32le(buf + 4, s1); + sph_enc32le(buf + 8, s2); + sph_enc32le(buf + 12, s3); + sph_enc32le(buf + 16, s4); + sph_enc32le(buf + 20, s5); + sph_enc32le(buf + 24, s6); + sph_enc32le(buf + 28, s7); + break; + } +} + +/* + * The main core functions inline the code with the COREx() macros. We + * use a helper file, included three times, which avoids code copying. + */ + +#undef PASSES +#define PASSES 3 +#include "haval_helper.c" + +#undef PASSES +#define PASSES 4 +#include "haval_helper.c" + +#undef PASSES +#define PASSES 5 +#include "haval_helper.c" + +/* ====================================================================== */ + +#define API(xxx, y) \ +void \ +sph_haval ## xxx ## _ ## y ## _init(void *cc) \ +{ \ + haval_init((sph_haval_context*)cc, xxx >> 5, y); \ +} \ + \ +void \ +sph_haval ## xxx ## _ ## y (void *cc, const void *data, size_t len) \ +{ \ + haval ## y((sph_haval_context*)cc, data, len); \ +} \ + \ +void \ +sph_haval ## xxx ## _ ## y ## _close(void *cc, void *dst) \ +{ \ + haval ## y ## _close((sph_haval_context*)cc, 0, 0, dst); \ +} \ + \ +void \ +sph_haval ## xxx ## _ ## y ## addbits_and_close( \ + void *cc, unsigned ub, unsigned n, void *dst) \ +{ \ + haval ## y ## _close((sph_haval_context*)cc, ub, n, dst); \ +} + +API(128, 3) +API(128, 4) +API(128, 5) +API(160, 3) +API(160, 4) +API(160, 5) +API(192, 3) +API(192, 4) +API(192, 5) +API(224, 3) +API(224, 4) +API(224, 5) +API(256, 3) +API(256, 4) +API(256, 5) + +#define RVAL do { \ + s0 = val[0]; \ + s1 = val[1]; \ + s2 = val[2]; \ + s3 = val[3]; \ + s4 = val[4]; \ + s5 = val[5]; \ + s6 = val[6]; \ + s7 = val[7]; \ + } while (0) + +#define WVAL do { \ + val[0] = s0; \ + val[1] = s1; \ + val[2] = s2; \ + val[3] = s3; \ + val[4] = s4; \ + val[5] = s5; \ + val[6] = s6; \ + val[7] = s7; \ + } while (0) + +#define INMSG(i) msg[i] + +/* see sph_haval.h */ +void +sph_haval_3_comp(const sph_u32 msg[32], sph_u32 val[8]) +{ + DSTATE; + + RVAL; + CORE3(INMSG); + WVAL; +} + +/* see sph_haval.h */ +void +sph_haval_4_comp(const sph_u32 msg[32], sph_u32 val[8]) +{ + DSTATE; + + RVAL; + CORE4(INMSG); + WVAL; +} + +/* see sph_haval.h */ +void +sph_haval_5_comp(const sph_u32 msg[32], sph_u32 val[8]) +{ + DSTATE; + + RVAL; + CORE5(INMSG); + WVAL; +} + diff --git a/sha3/sph_haval.h b/sha3/sph_haval.h new file mode 100644 index 000000000..6334a9226 --- /dev/null +++ b/sha3/sph_haval.h @@ -0,0 +1,969 @@ +/* $Id: sph_haval.h 218 2010-06-08 17:06:34Z tp $ */ +/** +* HAVAL interface. +* +* HAVAL is actually a family of 15 hash functions, depending on whether +* the internal computation uses 3, 4 or 5 passes, and on the output +* length, which is 128, 160, 192, 224 or 256 bits. This implementation +* provides interface functions for all 15, which internally map to +* three cores (depending on the number of passes). Note that output +* lengths other than 256 bits are not obtained by a simple truncation +* of a longer result; the requested length is encoded within the +* padding data. +* +* HAVAL was published in: Yuliang Zheng, Josef Pieprzyk and Jennifer +* Seberry: "HAVAL -- a one-way hashing algorithm with variable length +* of output", Advances in Cryptology -- AUSCRYPT'92, Lecture Notes in +* Computer Science, Vol.718, pp.83-104, Springer-Verlag, 1993. +* +* This paper, and a reference implementation, are available on the +* Calyptix web site: http://labs.calyptix.com/haval.php +* +* The HAVAL reference paper is quite unclear on the data encoding +* details, i.e. endianness (both byte order within a 32-bit word, and +* word order within a message block). This implementation has been +* made compatible with the reference implementation referenced above. +* +* @warning A collision for HAVAL-128/3 (HAVAL with three passes and +* 128-bit output) has been published; this function is thus considered +* as cryptographically broken. The status for other variants is unclear; +* use only with care. +* +* ==========================(LICENSE BEGIN)============================ +* +* Copyright (c) 2007-2010 Projet RNRT SAPHIR +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* ===========================(LICENSE END)============================= +* +* @file sph_haval.h +* @author Thomas Pornin +*/ + +#ifndef SPH_HAVAL_H__ +#define SPH_HAVAL_H__ + +#include +#include "sph_types.h" + +/** +* Output size (in bits) for HAVAL-128/3. +*/ +#define SPH_SIZE_haval128_3 128 + +/** +* Output size (in bits) for HAVAL-128/4. +*/ +#define SPH_SIZE_haval128_4 128 + +/** +* Output size (in bits) for HAVAL-128/5. +*/ +#define SPH_SIZE_haval128_5 128 + +/** +* Output size (in bits) for HAVAL-160/3. +*/ +#define SPH_SIZE_haval160_3 160 + +/** +* Output size (in bits) for HAVAL-160/4. +*/ +#define SPH_SIZE_haval160_4 160 + +/** +* Output size (in bits) for HAVAL-160/5. +*/ +#define SPH_SIZE_haval160_5 160 + +/** +* Output size (in bits) for HAVAL-192/3. +*/ +#define SPH_SIZE_haval192_3 192 + +/** +* Output size (in bits) for HAVAL-192/4. +*/ +#define SPH_SIZE_haval192_4 192 + +/** +* Output size (in bits) for HAVAL-192/5. +*/ +#define SPH_SIZE_haval192_5 192 + +/** +* Output size (in bits) for HAVAL-224/3. +*/ +#define SPH_SIZE_haval224_3 224 + +/** +* Output size (in bits) for HAVAL-224/4. +*/ +#define SPH_SIZE_haval224_4 224 + +/** +* Output size (in bits) for HAVAL-224/5. +*/ +#define SPH_SIZE_haval224_5 224 + +/** +* Output size (in bits) for HAVAL-256/3. +*/ +#define SPH_SIZE_haval256_3 256 + +/** +* Output size (in bits) for HAVAL-256/4. +*/ +#define SPH_SIZE_haval256_4 256 + +/** +* Output size (in bits) for HAVAL-256/5. +*/ +#define SPH_SIZE_haval256_5 256 + +/** +* This structure is a context for HAVAL computations: it contains the +* intermediate values and some data from the last entered block. Once +* a HAVAL computation has been performed, the context can be reused for +* another computation. +* +* The contents of this structure are private. A running HAVAL computation +* can be cloned by copying the context (e.g. with a simple +* memcpy()). +*/ +typedef struct { +#ifndef DOXYGEN_IGNORE +unsigned char buf[128]; /* first field, for alignment */ +sph_u32 s0, s1, s2, s3, s4, s5, s6, s7; +unsigned olen, passes; +#if SPH_64 +sph_u64 count; +#else +sph_u32 count_high, count_low; +#endif +#endif +} sph_haval_context; + +/** +* Type for a HAVAL-128/3 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval128_3_context; + +/** +* Type for a HAVAL-128/4 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval128_4_context; + +/** +* Type for a HAVAL-128/5 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval128_5_context; + +/** +* Type for a HAVAL-160/3 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval160_3_context; + +/** +* Type for a HAVAL-160/4 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval160_4_context; + +/** +* Type for a HAVAL-160/5 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval160_5_context; + +/** +* Type for a HAVAL-192/3 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval192_3_context; + +/** +* Type for a HAVAL-192/4 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval192_4_context; + +/** +* Type for a HAVAL-192/5 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval192_5_context; + +/** +* Type for a HAVAL-224/3 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval224_3_context; + +/** +* Type for a HAVAL-224/4 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval224_4_context; + +/** +* Type for a HAVAL-224/5 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval224_5_context; + +/** +* Type for a HAVAL-256/3 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval256_3_context; + +/** +* Type for a HAVAL-256/4 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval256_4_context; + +/** +* Type for a HAVAL-256/5 context (identical to the common context). +*/ +typedef sph_haval_context sph_haval256_5_context; + +/** +* Initialize the context for HAVAL-128/3. +* +* @param cc context to initialize (pointer to a +* sph_haval128_3_context structure) +*/ +void sph_haval128_3_init(void *cc); + +/** +* Process some data bytes for HAVAL-128/3. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-128/3 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval128_3(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-128/3 computation. The output buffer must be wide +* enough to accomodate the result (16 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-128/3 context +* @param dst the output buffer +*/ +void sph_haval128_3_close(void *cc, void *dst); + +/** +* Close a HAVAL-128/3 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (16 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-128/3 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval128_3_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-128/4. +* +* @param cc context to initialize (pointer to a +* sph_haval128_4_context structure) +*/ +void sph_haval128_4_init(void *cc); + +/** +* Process some data bytes for HAVAL-128/4. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-128/4 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval128_4(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-128/4 computation. The output buffer must be wide +* enough to accomodate the result (16 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-128/4 context +* @param dst the output buffer +*/ +void sph_haval128_4_close(void *cc, void *dst); + +/** +* Close a HAVAL-128/4 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (16 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-128/4 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval128_4_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-128/5. +* +* @param cc context to initialize (pointer to a +* sph_haval128_5_context structure) +*/ +void sph_haval128_5_init(void *cc); + +/** +* Process some data bytes for HAVAL-128/5. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-128/5 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval128_5(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-128/5 computation. The output buffer must be wide +* enough to accomodate the result (16 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-128/5 context +* @param dst the output buffer +*/ +void sph_haval128_5_close(void *cc, void *dst); + +/** +* Close a HAVAL-128/5 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (16 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-128/5 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval128_5_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-160/3. +* +* @param cc context to initialize (pointer to a +* sph_haval160_3_context structure) +*/ +void sph_haval160_3_init(void *cc); + +/** +* Process some data bytes for HAVAL-160/3. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-160/3 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval160_3(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-160/3 computation. The output buffer must be wide +* enough to accomodate the result (20 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-160/3 context +* @param dst the output buffer +*/ +void sph_haval160_3_close(void *cc, void *dst); + +/** +* Close a HAVAL-160/3 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (20 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-160/3 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval160_3_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-160/4. +* +* @param cc context to initialize (pointer to a +* sph_haval160_4_context structure) +*/ +void sph_haval160_4_init(void *cc); + +/** +* Process some data bytes for HAVAL-160/4. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-160/4 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval160_4(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-160/4 computation. The output buffer must be wide +* enough to accomodate the result (20 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-160/4 context +* @param dst the output buffer +*/ +void sph_haval160_4_close(void *cc, void *dst); + +/** +* Close a HAVAL-160/4 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (20 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-160/4 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval160_3_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-160/5. +* +* @param cc context to initialize (pointer to a +* sph_haval160_5_context structure) +*/ +void sph_haval160_5_init(void *cc); + +/** +* Process some data bytes for HAVAL-160/5. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-160/5 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval160_5(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-160/5 computation. The output buffer must be wide +* enough to accomodate the result (20 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-160/5 context +* @param dst the output buffer +*/ +void sph_haval160_5_close(void *cc, void *dst); + +/** +* Close a HAVAL-160/5 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (20 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-160/5 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval160_5_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-192/3. +* +* @param cc context to initialize (pointer to a +* sph_haval192_3_context structure) +*/ +void sph_haval192_3_init(void *cc); + +/** +* Process some data bytes for HAVAL-192/3. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-192/3 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval192_3(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-192/3 computation. The output buffer must be wide +* enough to accomodate the result (24 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-192/3 context +* @param dst the output buffer +*/ +void sph_haval192_3_close(void *cc, void *dst); + +/** +* Close a HAVAL-192/3 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (24 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-192/3 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval192_3_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-192/4. +* +* @param cc context to initialize (pointer to a +* sph_haval192_4_context structure) +*/ +void sph_haval192_4_init(void *cc); + +/** +* Process some data bytes for HAVAL-192/4. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-192/4 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval192_4(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-192/4 computation. The output buffer must be wide +* enough to accomodate the result (24 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-192/4 context +* @param dst the output buffer +*/ +void sph_haval192_4_close(void *cc, void *dst); + +/** +* Close a HAVAL-192/4 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (24 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-192/4 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval192_4_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-192/5. +* +* @param cc context to initialize (pointer to a +* sph_haval192_5_context structure) +*/ +void sph_haval192_5_init(void *cc); + +/** +* Process some data bytes for HAVAL-192/5. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-192/5 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval192_5(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-192/5 computation. The output buffer must be wide +* enough to accomodate the result (24 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-192/5 context +* @param dst the output buffer +*/ +void sph_haval192_5_close(void *cc, void *dst); + +/** +* Close a HAVAL-192/5 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (24 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-192/5 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval192_5_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-224/3. +* +* @param cc context to initialize (pointer to a +* sph_haval224_3_context structure) +*/ +void sph_haval224_3_init(void *cc); + +/** +* Process some data bytes for HAVAL-224/3. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-224/3 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval224_3(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-224/3 computation. The output buffer must be wide +* enough to accomodate the result (28 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-224/3 context +* @param dst the output buffer +*/ +void sph_haval224_3_close(void *cc, void *dst); + +/** +* Close a HAVAL-224/3 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (28 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-224/3 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval224_3_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-224/4. +* +* @param cc context to initialize (pointer to a +* sph_haval224_4_context structure) +*/ +void sph_haval224_4_init(void *cc); + +/** +* Process some data bytes for HAVAL-224/4. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-224/4 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval224_4(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-224/4 computation. The output buffer must be wide +* enough to accomodate the result (28 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-224/4 context +* @param dst the output buffer +*/ +void sph_haval224_4_close(void *cc, void *dst); + +/** +* Close a HAVAL-224/4 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (28 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-224/4 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval224_4_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-224/5. +* +* @param cc context to initialize (pointer to a +* sph_haval224_5_context structure) +*/ +void sph_haval224_5_init(void *cc); + +/** +* Process some data bytes for HAVAL-224/5. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-224/5 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval224_5(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-224/5 computation. The output buffer must be wide +* enough to accomodate the result (28 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-224/5 context +* @param dst the output buffer +*/ +void sph_haval224_5_close(void *cc, void *dst); + +/** +* Close a HAVAL-224/5 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (28 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-224/5 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval224_5_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-256/3. +* +* @param cc context to initialize (pointer to a +* sph_haval256_3_context structure) +*/ +void sph_haval256_3_init(void *cc); + +/** +* Process some data bytes for HAVAL-256/3. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-256/3 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval256_3(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-256/3 computation. The output buffer must be wide +* enough to accomodate the result (32 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-256/3 context +* @param dst the output buffer +*/ +void sph_haval256_3_close(void *cc, void *dst); + +/** +* Close a HAVAL-256/3 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (32 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-256/3 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval256_3_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-256/4. +* +* @param cc context to initialize (pointer to a +* sph_haval256_4_context structure) +*/ +void sph_haval256_4_init(void *cc); + +/** +* Process some data bytes for HAVAL-256/4. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-256/4 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval256_4(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-256/4 computation. The output buffer must be wide +* enough to accomodate the result (32 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-256/4 context +* @param dst the output buffer +*/ +void sph_haval256_4_close(void *cc, void *dst); + +/** +* Close a HAVAL-256/4 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (32 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-256/4 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval256_4_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Initialize the context for HAVAL-256/5. +* +* @param cc context to initialize (pointer to a +* sph_haval256_5_context structure) +*/ +void sph_haval256_5_init(void *cc); + +/** +* Process some data bytes for HAVAL-256/5. If len is 0, +* then this function does nothing. +* +* @param cc the HAVAL-256/5 context +* @param data the input data +* @param len the input data length (in bytes) +*/ +void sph_haval256_5(void *cc, const void *data, size_t len); + +/** +* Close a HAVAL-256/5 computation. The output buffer must be wide +* enough to accomodate the result (32 bytes). The context is automatically +* reinitialized. +* +* @param cc the HAVAL-256/5 context +* @param dst the output buffer +*/ +void sph_haval256_5_close(void *cc, void *dst); + +/** +* Close a HAVAL-256/5 computation. Up to 7 extra input bits may be added +* to the input message; these are the n upper bits of +* the ub byte (i.e. the first extra bit has value 128 in +* ub, the second extra bit has value 64, and so on). Other +* bits in ub are ignored. +* +* The output buffer must be wide enough to accomodate the result (32 +* bytes). The context is automatically reinitialized. +* +* @param cc the HAVAL-256/5 context +* @param ub the extra bits +* @param n the number of extra bits (0 to 7) +* @param dst the output buffer +*/ +void sph_haval256_5_addbits_and_close(void *cc, +unsigned ub, unsigned n, void *dst); + +/** +* Apply the HAVAL compression function on the provided data. The +* msg parameter contains the 32 32-bit input blocks, +* as numerical values (hence after the little-endian decoding). The +* val parameter contains the 8 32-bit input blocks for +* the compression function; the output is written in place in this +* array. This function uses three internal passes. +* +* @param msg the message block (32 values) +* @param val the function 256-bit input and output +*/ +void sph_haval_3_comp(const sph_u32 msg[32], sph_u32 val[8]); + +/** +* Apply the HAVAL compression function on the provided data. The +* msg parameter contains the 32 32-bit input blocks, +* as numerical values (hence after the little-endian decoding). The +* val parameter contains the 8 32-bit input blocks for +* the compression function; the output is written in place in this +* array. This function uses four internal passes. +* +* @param msg the message block (32 values) +* @param val the function 256-bit input and output +*/ +void sph_haval_4_comp(const sph_u32 msg[32], sph_u32 val[8]); + +/** +* Apply the HAVAL compression function on the provided data. The +* msg parameter contains the 32 32-bit input blocks, +* as numerical values (hence after the little-endian decoding). The +* val parameter contains the 8 32-bit input blocks for +* the compression function; the output is written in place in this +* array. This function uses five internal passes. +* +* @param msg the message block (32 values) +* @param val the function 256-bit input and output +*/ +void sph_haval_5_comp(const sph_u32 msg[32], sph_u32 val[8]); + +#endif diff --git a/sha3/sph_hefty1.c b/sha3/sph_hefty1.c index fadd151e6..8a8203cf4 100644 --- a/sha3/sph_hefty1.c +++ b/sha3/sph_hefty1.c @@ -32,6 +32,10 @@ #include #include +#ifdef _MSC_VER +#define inline __inline +#endif + #include "sph_hefty1.h" #define Min(A, B) (A <= B ? A : B) @@ -317,8 +321,8 @@ void HEFTY1_Update(HEFTY1_CTX *ctx, const void *buf, size_t len) uint64_t read = 0; while (len) { - uint64_t end = ctx->written % HEFTY1_BLOCK_BYTES; - uint64_t count = Min(len, HEFTY1_BLOCK_BYTES - end); + size_t end = (size_t)(ctx->written % HEFTY1_BLOCK_BYTES); + size_t count = Min(len, HEFTY1_BLOCK_BYTES - end); memcpy(&ctx->block[end], &((unsigned char *)buf)[read], count); len -= count; read += count; @@ -334,7 +338,7 @@ void HEFTY1_Final(unsigned char *digest, HEFTY1_CTX *ctx) assert(ctx); /* Pad message (FIPS 180 Section 5.1.1) */ - uint64_t used = ctx->written % HEFTY1_BLOCK_BYTES; + size_t used = (size_t)(ctx->written % HEFTY1_BLOCK_BYTES); ctx->block[used++] = 0x80; /* Append 1 to end of message */ if (used > HEFTY1_BLOCK_BYTES - 8) { /* We have already written into the last 64bits, so diff --git a/sha3/sph_panama.c b/sha3/sph_panama.c new file mode 100644 index 000000000..f3c27c77a --- /dev/null +++ b/sha3/sph_panama.c @@ -0,0 +1,334 @@ +/* $Id: panama.c 216 2010-06-08 09:46:57Z tp $ */ +/* + * PANAMA implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_panama.h" + +#define LVAR17(b) sph_u32 \ + b ## 0, b ## 1, b ## 2, b ## 3, b ## 4, b ## 5, \ + b ## 6, b ## 7, b ## 8, b ## 9, b ## 10, b ## 11, \ + b ## 12, b ## 13, b ## 14, b ## 15, b ## 16; + +#define LVARS \ + LVAR17(a) \ + LVAR17(g) \ + LVAR17(p) \ + LVAR17(t) + +#define M17(macro) do { \ + macro( 0, 1, 2, 4); \ + macro( 1, 2, 3, 5); \ + macro( 2, 3, 4, 6); \ + macro( 3, 4, 5, 7); \ + macro( 4, 5, 6, 8); \ + macro( 5, 6, 7, 9); \ + macro( 6, 7, 8, 10); \ + macro( 7, 8, 9, 11); \ + macro( 8, 9, 10, 12); \ + macro( 9, 10, 11, 13); \ + macro(10, 11, 12, 14); \ + macro(11, 12, 13, 15); \ + macro(12, 13, 14, 16); \ + macro(13, 14, 15, 0); \ + macro(14, 15, 16, 1); \ + macro(15, 16, 0, 2); \ + macro(16, 0, 1, 3); \ + } while (0) + +#define BUPDATE1(n0, n2) do { \ + sc->buffer[ptr24][n0] ^= sc->buffer[ptr31][n2]; \ + sc->buffer[ptr31][n2] ^= INW1(n2); \ + } while (0) + +#define BUPDATE do { \ + BUPDATE1(0, 2); \ + BUPDATE1(1, 3); \ + BUPDATE1(2, 4); \ + BUPDATE1(3, 5); \ + BUPDATE1(4, 6); \ + BUPDATE1(5, 7); \ + BUPDATE1(6, 0); \ + BUPDATE1(7, 1); \ + } while (0) + +#define RSTATE(n0, n1, n2, n4) (a ## n0 = sc->state[n0]) + +#define WSTATE(n0, n1, n2, n4) (sc->state[n0] = a ## n0) + +#define GAMMA(n0, n1, n2, n4) \ + (g ## n0 = a ## n0 ^ (a ## n1 | SPH_T32(~a ## n2))) + +#define PI_ALL do { \ + p0 = g0; \ + p1 = SPH_ROTL32( g7, 1); \ + p2 = SPH_ROTL32(g14, 3); \ + p3 = SPH_ROTL32( g4, 6); \ + p4 = SPH_ROTL32(g11, 10); \ + p5 = SPH_ROTL32( g1, 15); \ + p6 = SPH_ROTL32( g8, 21); \ + p7 = SPH_ROTL32(g15, 28); \ + p8 = SPH_ROTL32( g5, 4); \ + p9 = SPH_ROTL32(g12, 13); \ + p10 = SPH_ROTL32( g2, 23); \ + p11 = SPH_ROTL32( g9, 2); \ + p12 = SPH_ROTL32(g16, 14); \ + p13 = SPH_ROTL32( g6, 27); \ + p14 = SPH_ROTL32(g13, 9); \ + p15 = SPH_ROTL32( g3, 24); \ + p16 = SPH_ROTL32(g10, 8); \ + } while (0) + +#define THETA(n0, n1, n2, n4) \ + (t ## n0 = p ## n0 ^ p ## n1 ^ p ## n4) + +#define SIGMA_ALL do { \ + a0 = t0 ^ 1; \ + a1 = t1 ^ INW2(0); \ + a2 = t2 ^ INW2(1); \ + a3 = t3 ^ INW2(2); \ + a4 = t4 ^ INW2(3); \ + a5 = t5 ^ INW2(4); \ + a6 = t6 ^ INW2(5); \ + a7 = t7 ^ INW2(6); \ + a8 = t8 ^ INW2(7); \ + a9 = t9 ^ sc->buffer[ptr16][0]; \ + a10 = t10 ^ sc->buffer[ptr16][1]; \ + a11 = t11 ^ sc->buffer[ptr16][2]; \ + a12 = t12 ^ sc->buffer[ptr16][3]; \ + a13 = t13 ^ sc->buffer[ptr16][4]; \ + a14 = t14 ^ sc->buffer[ptr16][5]; \ + a15 = t15 ^ sc->buffer[ptr16][6]; \ + a16 = t16 ^ sc->buffer[ptr16][7]; \ + } while (0) + +#define PANAMA_STEP do { \ + unsigned ptr16, ptr24, ptr31; \ + \ + ptr24 = (ptr0 - 8) & 31; \ + ptr31 = (ptr0 - 1) & 31; \ + BUPDATE; \ + M17(GAMMA); \ + PI_ALL; \ + M17(THETA); \ + ptr16 = ptr0 ^ 16; \ + SIGMA_ALL; \ + ptr0 = ptr31; \ + } while (0) + +/* + * These macros are used to compute + */ +#define INC0 1 +#define INC1 2 +#define INC2 3 +#define INC3 4 +#define INC4 5 +#define INC5 6 +#define INC6 7 +#define INC7 8 + +/* + * Push data by blocks of 32 bytes. "pbuf" must be 32-bit aligned. Each + * iteration processes 32 data bytes; "num" contains the number of + * iterations. + */ +static void +panama_push(sph_panama_context *sc, const unsigned char *pbuf, size_t num) +{ + LVARS + unsigned ptr0; +#if SPH_LITTLE_FAST +#define INW1(i) sph_dec32le_aligned(pbuf + 4 * (i)) +#else + sph_u32 X_var[8]; +#define INW1(i) X_var[i] +#endif +#define INW2(i) INW1(i) + + M17(RSTATE); + ptr0 = sc->buffer_ptr; + while (num -- > 0) { +#if !SPH_LITTLE_FAST + int i; + + for (i = 0; i < 8; i ++) + X_var[i] = sph_dec32le_aligned(pbuf + 4 * (i)); +#endif + PANAMA_STEP; + pbuf = (const unsigned char *)pbuf + 32; + } + M17(WSTATE); + sc->buffer_ptr = ptr0; + +#undef INW1 +#undef INW2 +} + +/* + * Perform the "pull" operation repeatedly ("num" times). The hash output + * will be extracted from the state afterwards. + */ +static void +panama_pull(sph_panama_context *sc, unsigned num) +{ + LVARS + unsigned ptr0; +#define INW1(i) INW_H1(INC ## i) +#define INW_H1(i) INW_H2(i) +#define INW_H2(i) a ## i +#define INW2(i) sc->buffer[ptr4][i] + + M17(RSTATE); + ptr0 = sc->buffer_ptr; + while (num -- > 0) { + unsigned ptr4; + + ptr4 = (ptr0 + 4) & 31; + PANAMA_STEP; + } + M17(WSTATE); + +#undef INW1 +#undef INW_H1 +#undef INW_H2 +#undef INW2 +} + +/* see sph_panama.h */ +void +sph_panama_init(void *cc) +{ + sph_panama_context *sc; + + sc = cc; + /* + * This is not completely conformant, but "it will work + * everywhere". Initial state consists of zeroes everywhere. + * Conceptually, the sph_u32 type may have padding bits which + * must not be set to 0; but such an architecture remains to + * be seen. + */ + sc->data_ptr = 0; + memset(sc->buffer, 0, sizeof sc->buffer); + sc->buffer_ptr = 0; + memset(sc->state, 0, sizeof sc->state); +} + +#ifdef SPH_UPTR +static void +panama_short(void *cc, const void *data, size_t len) +#else +void +sph_panama(void *cc, const void *data, size_t len) +#endif +{ + sph_panama_context *sc; + unsigned current; + + sc = cc; + current = sc->data_ptr; + while (len > 0) { + unsigned clen; + + clen = (sizeof sc->data) - current; + if (clen > len) + clen = len; + memcpy(sc->data + current, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + current += clen; + if (current == sizeof sc->data) { + current = 0; + panama_push(sc, sc->data, 1); + } + } + sc->data_ptr = current; +} + +#ifdef SPH_UPTR +/* see sph_panama.h */ +void +sph_panama(void *cc, const void *data, size_t len) +{ + sph_panama_context *sc; + unsigned current; + size_t rlen; + + if (len < (2 * sizeof sc->data)) { + panama_short(cc, data, len); + return; + } + sc = cc; + current = sc->data_ptr; + if (current > 0) { + unsigned t; + + t = (sizeof sc->data) - current; + panama_short(sc, data, t); + data = (const unsigned char *)data + t; + len -= t; + } +#if !SPH_UNALIGNED + if (((SPH_UPTR)data & 3) != 0) { + panama_short(sc, data, len); + return; + } +#endif + panama_push(sc, data, len >> 5); + rlen = len & 31; + if (rlen > 0) + memcpy(sc->data, + (const unsigned char *)data + len - rlen, rlen); + sc->data_ptr = rlen; +} +#endif + +/* see sph_panama.h */ +void +sph_panama_close(void *cc, void *dst) +{ + sph_panama_context *sc; + unsigned current; + int i; + + sc = cc; + current = sc->data_ptr; + sc->data[current ++] = 0x01; + memset(sc->data + current, 0, (sizeof sc->data) - current); + panama_push(sc, sc->data, 1); + panama_pull(sc, 32); + for (i = 0; i < 8; i ++) + sph_enc32le((unsigned char *)dst + 4 * i, sc->state[i + 9]); + sph_panama_init(sc); +} diff --git a/sha3/sph_panama.h b/sha3/sph_panama.h new file mode 100644 index 000000000..e4dc1073a --- /dev/null +++ b/sha3/sph_panama.h @@ -0,0 +1,118 @@ +/* $Id: sph_panama.h 154 2010-04-26 17:00:24Z tp $ */ +/** + * PANAMA interface. + * + * PANAMA has been published in: J. Daemen and C. Clapp, "Fast Hashing + * and Stream Encryption with PANAMA", Fast Software Encryption - + * FSE'98, LNCS 1372, Springer (1998), pp. 60--74. + * + * PANAMA is not fully defined with regards to endianness and related + * topics. This implementation follows strict little-endian conventions: + *
      + *
    • Each 32-byte input block is split into eight 32-bit words, the + * first (leftmost) word being numbered 0.
    • + *
    • Each such 32-bit word is decoded from memory in little-endian + * convention.
    • + *
    • The additional padding bit equal to "1" is added by considering + * the least significant bit in a byte to come first; practically, this + * means that a single byte of value 0x01 is appended to the (byte-oriented) + * message, and then 0 to 31 bytes of value 0x00.
    • + *
    • The output consists of eight 32-bit words; the word numbered 0 is + * written first (in leftmost position) and it is encoded in little-endian + * convention. + *
    + * With these conventions, PANAMA is sometimes known as "PANAMA-LE". The + * PANAMA reference implementation uses our conventions for input, but + * prescribes no convention for output. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_panama.h + * @author Thomas Pornin + */ + +#ifndef SPH_PANAMA_H__ +#define SPH_PANAMA_H__ + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for PANAMA. + */ +#define SPH_SIZE_panama 256 + +/** + * This structure is a context for PANAMA computations: it contains the + * intermediate values and some data from the last entered block. Once + * a PANAMA computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running PANAMA computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char data[32]; /* first field, for alignment */ + unsigned data_ptr; + + sph_u32 buffer[32][8]; + unsigned buffer_ptr; + + sph_u32 state[17]; +#endif +} sph_panama_context; + +/** + * Initialize a PANAMA context. This process performs no memory allocation. + * + * @param cc the PANAMA context (pointer to a sph_panama_context) + */ +void sph_panama_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the PANAMA context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_panama(void *cc, const void *data, size_t len); + +/** + * Terminate the current PANAMA computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the PANAMA context + * @param dst the destination buffer + */ +void sph_panama_close(void *cc, void *dst); + +#endif diff --git a/sha3/sph_radiogatun.c b/sha3/sph_radiogatun.c new file mode 100644 index 000000000..888b028f9 --- /dev/null +++ b/sha3/sph_radiogatun.c @@ -0,0 +1,1003 @@ +/* $Id: radiogatun.c 226 2010-06-16 17:28:08Z tp $ */ +/* + * RadioGatun implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_radiogatun.h" + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_RADIOGATUN +#define SPH_SMALL_FOOTPRINT_RADIOGATUN 1 +#endif + +/* ======================================================================= */ +/* + * The core macros. We want to unroll 13 successive rounds so that the + * belt rotation becomes pure routing, solved at compilation time, with + * no unnecessary copying. We also wish all state variables to be + * independant local variables, so that the C compiler becomes free to + * map these on registers at it sees fit. This requires some heavy + * preprocessor trickeries, including a full addition macro modulo 13. + * + * These macros are size-independent. Some macros must be defined before + * use: + * WT evaluates to the type for a word (32-bit or 64-bit) + * T truncates a value to the proper word size + * ROR(x, n) right rotation of a word x, with explicit modular + * reduction of the rotation count n by the word size + * INW(i, j) input word j (0, 1, or 2) of block i (0 to 12) + * + * For INW, the input buffer is pointed to by "buf" which has type + * "const unsigned char *". + */ + +#define MUL19(action) do { \ + action(0); \ + action(1); \ + action(2); \ + action(3); \ + action(4); \ + action(5); \ + action(6); \ + action(7); \ + action(8); \ + action(9); \ + action(10); \ + action(11); \ + action(12); \ + action(13); \ + action(14); \ + action(15); \ + action(16); \ + action(17); \ + action(18); \ + } while (0) + +#define DECL19(b) b ## 0, b ## 1, b ## 2, b ## 3, b ## 4, b ## 5, \ + b ## 6, b ## 7, b ## 8, b ## 9, b ## 10, b ## 11, \ + b ## 12, b ## 13, b ## 14, b ## 15, b ## 16, \ + b ## 17, b ## 18 + +#define M19_T7(i) M19_T7_(i) +#define M19_T7_(i) M19_T7_ ## i +#define M19_T7_0 0 +#define M19_T7_1 7 +#define M19_T7_2 14 +#define M19_T7_3 2 +#define M19_T7_4 9 +#define M19_T7_5 16 +#define M19_T7_6 4 +#define M19_T7_7 11 +#define M19_T7_8 18 +#define M19_T7_9 6 +#define M19_T7_10 13 +#define M19_T7_11 1 +#define M19_T7_12 8 +#define M19_T7_13 15 +#define M19_T7_14 3 +#define M19_T7_15 10 +#define M19_T7_16 17 +#define M19_T7_17 5 +#define M19_T7_18 12 + +#define M19_A1(i) M19_A1_(i) +#define M19_A1_(i) M19_A1_ ## i +#define M19_A1_0 1 +#define M19_A1_1 2 +#define M19_A1_2 3 +#define M19_A1_3 4 +#define M19_A1_4 5 +#define M19_A1_5 6 +#define M19_A1_6 7 +#define M19_A1_7 8 +#define M19_A1_8 9 +#define M19_A1_9 10 +#define M19_A1_10 11 +#define M19_A1_11 12 +#define M19_A1_12 13 +#define M19_A1_13 14 +#define M19_A1_14 15 +#define M19_A1_15 16 +#define M19_A1_16 17 +#define M19_A1_17 18 +#define M19_A1_18 0 + +#define M19_A2(i) M19_A2_(i) +#define M19_A2_(i) M19_A2_ ## i +#define M19_A2_0 2 +#define M19_A2_1 3 +#define M19_A2_2 4 +#define M19_A2_3 5 +#define M19_A2_4 6 +#define M19_A2_5 7 +#define M19_A2_6 8 +#define M19_A2_7 9 +#define M19_A2_8 10 +#define M19_A2_9 11 +#define M19_A2_10 12 +#define M19_A2_11 13 +#define M19_A2_12 14 +#define M19_A2_13 15 +#define M19_A2_14 16 +#define M19_A2_15 17 +#define M19_A2_16 18 +#define M19_A2_17 0 +#define M19_A2_18 1 + +#define M19_A4(i) M19_A4_(i) +#define M19_A4_(i) M19_A4_ ## i +#define M19_A4_0 4 +#define M19_A4_1 5 +#define M19_A4_2 6 +#define M19_A4_3 7 +#define M19_A4_4 8 +#define M19_A4_5 9 +#define M19_A4_6 10 +#define M19_A4_7 11 +#define M19_A4_8 12 +#define M19_A4_9 13 +#define M19_A4_10 14 +#define M19_A4_11 15 +#define M19_A4_12 16 +#define M19_A4_13 17 +#define M19_A4_14 18 +#define M19_A4_15 0 +#define M19_A4_16 1 +#define M19_A4_17 2 +#define M19_A4_18 3 + +#define ACC_a(i) ACC_a_(i) +#define ACC_a_(i) a ## i +#define ACC_atmp(i) ACC_atmp_(i) +#define ACC_atmp_(i) atmp ## i + +#define MILL1(i) (atmp ## i = a ## i ^ T(ACC_a(M19_A1(i)) \ + | ~ACC_a(M19_A2(i)))) +#define MILL2(i) (a ## i = ROR(ACC_atmp(M19_T7(i)), ((i * (i + 1)) >> 1))) +#define MILL3(i) (atmp ## i = a ## i ^ ACC_a(M19_A1(i)) ^ ACC_a(M19_A4(i))) +#define MILL4(i) (a ## i = atmp ## i ^ (i == 0)) + +#define MILL do { \ + WT DECL19(atmp); \ + MUL19(MILL1); \ + MUL19(MILL2); \ + MUL19(MILL3); \ + MUL19(MILL4); \ + } while (0) + +#define DECL13(b) b ## 0 ## _0, b ## 0 ## _1, b ## 0 ## _2, \ + b ## 1 ## _0, b ## 1 ## _1, b ## 1 ## _2, \ + b ## 2 ## _0, b ## 2 ## _1, b ## 2 ## _2, \ + b ## 3 ## _0, b ## 3 ## _1, b ## 3 ## _2, \ + b ## 4 ## _0, b ## 4 ## _1, b ## 4 ## _2, \ + b ## 5 ## _0, b ## 5 ## _1, b ## 5 ## _2, \ + b ## 6 ## _0, b ## 6 ## _1, b ## 6 ## _2, \ + b ## 7 ## _0, b ## 7 ## _1, b ## 7 ## _2, \ + b ## 8 ## _0, b ## 8 ## _1, b ## 8 ## _2, \ + b ## 9 ## _0, b ## 9 ## _1, b ## 9 ## _2, \ + b ## 10 ## _0, b ## 10 ## _1, b ## 10 ## _2, \ + b ## 11 ## _0, b ## 11 ## _1, b ## 11 ## _2, \ + b ## 12 ## _0, b ## 12 ## _1, b ## 12 ## _2 + +#define M13_A(i, j) M13_A_(i, j) +#define M13_A_(i, j) M13_A_ ## i ## _ ## j +#define M13_A_0_0 0 +#define M13_A_0_1 1 +#define M13_A_0_2 2 +#define M13_A_0_3 3 +#define M13_A_0_4 4 +#define M13_A_0_5 5 +#define M13_A_0_6 6 +#define M13_A_0_7 7 +#define M13_A_0_8 8 +#define M13_A_0_9 9 +#define M13_A_0_10 10 +#define M13_A_0_11 11 +#define M13_A_0_12 12 +#define M13_A_1_0 1 +#define M13_A_1_1 2 +#define M13_A_1_2 3 +#define M13_A_1_3 4 +#define M13_A_1_4 5 +#define M13_A_1_5 6 +#define M13_A_1_6 7 +#define M13_A_1_7 8 +#define M13_A_1_8 9 +#define M13_A_1_9 10 +#define M13_A_1_10 11 +#define M13_A_1_11 12 +#define M13_A_1_12 0 +#define M13_A_2_0 2 +#define M13_A_2_1 3 +#define M13_A_2_2 4 +#define M13_A_2_3 5 +#define M13_A_2_4 6 +#define M13_A_2_5 7 +#define M13_A_2_6 8 +#define M13_A_2_7 9 +#define M13_A_2_8 10 +#define M13_A_2_9 11 +#define M13_A_2_10 12 +#define M13_A_2_11 0 +#define M13_A_2_12 1 +#define M13_A_3_0 3 +#define M13_A_3_1 4 +#define M13_A_3_2 5 +#define M13_A_3_3 6 +#define M13_A_3_4 7 +#define M13_A_3_5 8 +#define M13_A_3_6 9 +#define M13_A_3_7 10 +#define M13_A_3_8 11 +#define M13_A_3_9 12 +#define M13_A_3_10 0 +#define M13_A_3_11 1 +#define M13_A_3_12 2 +#define M13_A_4_0 4 +#define M13_A_4_1 5 +#define M13_A_4_2 6 +#define M13_A_4_3 7 +#define M13_A_4_4 8 +#define M13_A_4_5 9 +#define M13_A_4_6 10 +#define M13_A_4_7 11 +#define M13_A_4_8 12 +#define M13_A_4_9 0 +#define M13_A_4_10 1 +#define M13_A_4_11 2 +#define M13_A_4_12 3 +#define M13_A_5_0 5 +#define M13_A_5_1 6 +#define M13_A_5_2 7 +#define M13_A_5_3 8 +#define M13_A_5_4 9 +#define M13_A_5_5 10 +#define M13_A_5_6 11 +#define M13_A_5_7 12 +#define M13_A_5_8 0 +#define M13_A_5_9 1 +#define M13_A_5_10 2 +#define M13_A_5_11 3 +#define M13_A_5_12 4 +#define M13_A_6_0 6 +#define M13_A_6_1 7 +#define M13_A_6_2 8 +#define M13_A_6_3 9 +#define M13_A_6_4 10 +#define M13_A_6_5 11 +#define M13_A_6_6 12 +#define M13_A_6_7 0 +#define M13_A_6_8 1 +#define M13_A_6_9 2 +#define M13_A_6_10 3 +#define M13_A_6_11 4 +#define M13_A_6_12 5 +#define M13_A_7_0 7 +#define M13_A_7_1 8 +#define M13_A_7_2 9 +#define M13_A_7_3 10 +#define M13_A_7_4 11 +#define M13_A_7_5 12 +#define M13_A_7_6 0 +#define M13_A_7_7 1 +#define M13_A_7_8 2 +#define M13_A_7_9 3 +#define M13_A_7_10 4 +#define M13_A_7_11 5 +#define M13_A_7_12 6 +#define M13_A_8_0 8 +#define M13_A_8_1 9 +#define M13_A_8_2 10 +#define M13_A_8_3 11 +#define M13_A_8_4 12 +#define M13_A_8_5 0 +#define M13_A_8_6 1 +#define M13_A_8_7 2 +#define M13_A_8_8 3 +#define M13_A_8_9 4 +#define M13_A_8_10 5 +#define M13_A_8_11 6 +#define M13_A_8_12 7 +#define M13_A_9_0 9 +#define M13_A_9_1 10 +#define M13_A_9_2 11 +#define M13_A_9_3 12 +#define M13_A_9_4 0 +#define M13_A_9_5 1 +#define M13_A_9_6 2 +#define M13_A_9_7 3 +#define M13_A_9_8 4 +#define M13_A_9_9 5 +#define M13_A_9_10 6 +#define M13_A_9_11 7 +#define M13_A_9_12 8 +#define M13_A_10_0 10 +#define M13_A_10_1 11 +#define M13_A_10_2 12 +#define M13_A_10_3 0 +#define M13_A_10_4 1 +#define M13_A_10_5 2 +#define M13_A_10_6 3 +#define M13_A_10_7 4 +#define M13_A_10_8 5 +#define M13_A_10_9 6 +#define M13_A_10_10 7 +#define M13_A_10_11 8 +#define M13_A_10_12 9 +#define M13_A_11_0 11 +#define M13_A_11_1 12 +#define M13_A_11_2 0 +#define M13_A_11_3 1 +#define M13_A_11_4 2 +#define M13_A_11_5 3 +#define M13_A_11_6 4 +#define M13_A_11_7 5 +#define M13_A_11_8 6 +#define M13_A_11_9 7 +#define M13_A_11_10 8 +#define M13_A_11_11 9 +#define M13_A_11_12 10 +#define M13_A_12_0 12 +#define M13_A_12_1 0 +#define M13_A_12_2 1 +#define M13_A_12_3 2 +#define M13_A_12_4 3 +#define M13_A_12_5 4 +#define M13_A_12_6 5 +#define M13_A_12_7 6 +#define M13_A_12_8 7 +#define M13_A_12_9 8 +#define M13_A_12_10 9 +#define M13_A_12_11 10 +#define M13_A_12_12 11 + +#define M13_N(i) M13_N_(i) +#define M13_N_(i) M13_N_ ## i +#define M13_N_0 12 +#define M13_N_1 11 +#define M13_N_2 10 +#define M13_N_3 9 +#define M13_N_4 8 +#define M13_N_5 7 +#define M13_N_6 6 +#define M13_N_7 5 +#define M13_N_8 4 +#define M13_N_9 3 +#define M13_N_10 2 +#define M13_N_11 1 +#define M13_N_12 0 + +#define ACC_b(i, k) ACC_b_(i, k) +#define ACC_b_(i, k) b ## i ## _ ## k + +#define ROUND_ELT(k, s) do { \ + if ((bj += 3) == 39) \ + bj = 0; \ + sc->b[bj + s] ^= a ## k; \ + } while (0) + +#define ROUND_SF(j) do { \ + size_t bj = (j) * 3; \ + ROUND_ELT(1, 0); \ + ROUND_ELT(2, 1); \ + ROUND_ELT(3, 2); \ + ROUND_ELT(4, 0); \ + ROUND_ELT(5, 1); \ + ROUND_ELT(6, 2); \ + ROUND_ELT(7, 0); \ + ROUND_ELT(8, 1); \ + ROUND_ELT(9, 2); \ + ROUND_ELT(10, 0); \ + ROUND_ELT(11, 1); \ + ROUND_ELT(12, 2); \ + MILL; \ + bj = (j) * 3; \ + a ## 13 ^= sc->b[bj + 0]; \ + a ## 14 ^= sc->b[bj + 1]; \ + a ## 15 ^= sc->b[bj + 2]; \ + } while (0) + +#define INPUT_SF(j, p0, p1, p2) do { \ + size_t bj = ((j) + 1) * 3; \ + if (bj == 39) \ + bj = 0; \ + sc->b[bj + 0] ^= (p0); \ + sc->b[bj + 1] ^= (p1); \ + sc->b[bj + 2] ^= (p2); \ + a16 ^= (p0); \ + a17 ^= (p1); \ + a18 ^= (p2); \ + } while (0) + + +#if SPH_SMALL_FOOTPRINT_RADIOGATUN + +#define ROUND ROUND_SF +#define INPUT INPUT_SF + +#else + +/* + * Round function R, on base j. The value j is such that B[0] is actually + * b[j] after the initial rotation. On the 13-round macro, j has the + * successive values 12, 11, 10... 1, 0. + */ +#define ROUND(j) do { \ + ACC_b(M13_A(1, j), 0) ^= a ## 1; \ + ACC_b(M13_A(2, j), 1) ^= a ## 2; \ + ACC_b(M13_A(3, j), 2) ^= a ## 3; \ + ACC_b(M13_A(4, j), 0) ^= a ## 4; \ + ACC_b(M13_A(5, j), 1) ^= a ## 5; \ + ACC_b(M13_A(6, j), 2) ^= a ## 6; \ + ACC_b(M13_A(7, j), 0) ^= a ## 7; \ + ACC_b(M13_A(8, j), 1) ^= a ## 8; \ + ACC_b(M13_A(9, j), 2) ^= a ## 9; \ + ACC_b(M13_A(10, j), 0) ^= a ## 10; \ + ACC_b(M13_A(11, j), 1) ^= a ## 11; \ + ACC_b(M13_A(12, j), 2) ^= a ## 12; \ + MILL; \ + a ## 13 ^= ACC_b(j, 0); \ + a ## 14 ^= ACC_b(j, 1); \ + a ## 15 ^= ACC_b(j, 2); \ + } while (0) + +#define INPUT(j, p0, p1, p2) do { \ + ACC_b(M13_A(1, j), 0) ^= (p0); \ + ACC_b(M13_A(1, j), 1) ^= (p1); \ + ACC_b(M13_A(1, j), 2) ^= (p2); \ + a16 ^= (p0); \ + a17 ^= (p1); \ + a18 ^= (p2); \ + } while (0) + +#endif + +#define MUL13(action) do { \ + action(0); \ + action(1); \ + action(2); \ + action(3); \ + action(4); \ + action(5); \ + action(6); \ + action(7); \ + action(8); \ + action(9); \ + action(10); \ + action(11); \ + action(12); \ + } while (0) + +#define MILL_READ_ELT(i) do { \ + a ## i = sc->a[i]; \ + } while (0) + +#define MILL_WRITE_ELT(i) do { \ + sc->a[i] = a ## i; \ + } while (0) + +#define STATE_READ_SF do { \ + MUL19(MILL_READ_ELT); \ + } while (0) + +#define STATE_WRITE_SF do { \ + MUL19(MILL_WRITE_ELT); \ + } while (0) + +#define PUSH13_SF do { \ + WT DECL19(a); \ + const unsigned char *buf; \ + \ + buf = data; \ + STATE_READ_SF; \ + while (len >= sizeof sc->data) { \ + size_t mk; \ + for (mk = 13; mk > 0; mk --) { \ + WT p0 = INW(0, 0); \ + WT p1 = INW(0, 1); \ + WT p2 = INW(0, 2); \ + INPUT_SF(mk - 1, p0, p1, p2); \ + ROUND_SF(mk - 1); \ + buf += (sizeof sc->data) / 13; \ + len -= (sizeof sc->data) / 13; \ + } \ + } \ + STATE_WRITE_SF; \ + return len; \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_RADIOGATUN + +#define STATE_READ STATE_READ_SF +#define STATE_WRITE STATE_WRITE_SF +#define PUSH13 PUSH13_SF + +#else + +#define BELT_READ_ELT(i) do { \ + b ## i ## _0 = sc->b[3 * i + 0]; \ + b ## i ## _1 = sc->b[3 * i + 1]; \ + b ## i ## _2 = sc->b[3 * i + 2]; \ + } while (0) + +#define BELT_WRITE_ELT(i) do { \ + sc->b[3 * i + 0] = b ## i ## _0; \ + sc->b[3 * i + 1] = b ## i ## _1; \ + sc->b[3 * i + 2] = b ## i ## _2; \ + } while (0) + +#define STATE_READ do { \ + MUL13(BELT_READ_ELT); \ + MUL19(MILL_READ_ELT); \ + } while (0) + +#define STATE_WRITE do { \ + MUL13(BELT_WRITE_ELT); \ + MUL19(MILL_WRITE_ELT); \ + } while (0) + +/* + * Input data by chunks of 13*3 blocks. This is the body of the + * radiogatun32_push13() and radiogatun64_push13() functions. + */ +#define PUSH13 do { \ + WT DECL19(a), DECL13(b); \ + const unsigned char *buf; \ + \ + buf = data; \ + STATE_READ; \ + while (len >= sizeof sc->data) { \ + WT p0, p1, p2; \ + MUL13(PUSH13_ELT); \ + buf += sizeof sc->data; \ + len -= sizeof sc->data; \ + } \ + STATE_WRITE; \ + return len; \ + } while (0) + +#define PUSH13_ELT(k) do { \ + p0 = INW(k, 0); \ + p1 = INW(k, 1); \ + p2 = INW(k, 2); \ + INPUT(M13_N(k), p0, p1, p2); \ + ROUND(M13_N(k)); \ + } while (0) + +#endif + +#define BLANK13_SF do { \ + size_t mk = 13; \ + while (mk -- > 0) \ + ROUND_SF(mk); \ + } while (0) + +#define BLANK1_SF do { \ + WT tmp0, tmp1, tmp2; \ + ROUND_SF(12); \ + tmp0 = sc->b[36]; \ + tmp1 = sc->b[37]; \ + tmp2 = sc->b[38]; \ + memmove(sc->b + 3, sc->b, 36 * sizeof sc->b[0]); \ + sc->b[0] = tmp0; \ + sc->b[1] = tmp1; \ + sc->b[2] = tmp2; \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_RADIOGATUN + +#define BLANK13 BLANK13_SF +#define BLANK1 BLANK1_SF + +#else + +/* + * Run 13 blank rounds. This macro expects the "a" and "b" state variables + * to be alread declared. + */ +#define BLANK13 MUL13(BLANK13_ELT) + +#define BLANK13_ELT(k) ROUND(M13_N(k)) + +#define MUL12(action) do { \ + action(0); \ + action(1); \ + action(2); \ + action(3); \ + action(4); \ + action(5); \ + action(6); \ + action(7); \ + action(8); \ + action(9); \ + action(10); \ + action(11); \ + } while (0) + +/* + * Run a single blank round, and physically rotate the belt. This is used + * for the last blank rounds, and the output rounds. This macro expects the + * "a" abd "b" state variables to be already declared. + */ +#define BLANK1 do { \ + WT tmp0, tmp1, tmp2; \ + ROUND(12); \ + tmp0 = b0_0; \ + tmp1 = b0_1; \ + tmp2 = b0_2; \ + MUL12(BLANK1_ELT); \ + b1_0 = tmp0; \ + b1_1 = tmp1; \ + b1_2 = tmp2; \ + } while (0) + +#define BLANK1_ELT(i) do { \ + ACC_b(M13_A(M13_N(i), 1), 0) = ACC_b(M13_N(i), 0); \ + ACC_b(M13_A(M13_N(i), 1), 1) = ACC_b(M13_N(i), 1); \ + ACC_b(M13_A(M13_N(i), 1), 2) = ACC_b(M13_N(i), 2); \ + } while (0) + +#endif + +#define NO_TOKEN + +/* + * Perform padding, then blank rounds, then output some words. This is + * the body of sph_radiogatun32_close() and sph_radiogatun64_close(). + */ +#define CLOSE_SF(width) CLOSE_GEN(width, \ + NO_TOKEN, STATE_READ_SF, BLANK1_SF, BLANK13_SF) + +#if SPH_SMALL_FOOTPRINT_RADIOGATUN +#define CLOSE CLOSE_SF +#else +#define CLOSE(width) CLOSE_GEN(width, \ + WT DECL13(b);, STATE_READ, BLANK1, BLANK13) +#endif + +#define CLOSE_GEN(width, WTb13, state_read, blank1, blank13) do { \ + unsigned ptr, num; \ + unsigned char *out; \ + WT DECL19(a); \ + WTb13 \ + \ + ptr = sc->data_ptr; \ + sc->data[ptr ++] = 0x01; \ + memset(sc->data + ptr, 0, (sizeof sc->data) - ptr); \ + radiogatun ## width ## _push13(sc, sc->data, sizeof sc->data); \ + \ + num = 17; \ + for (;;) { \ + ptr += 3 * (width >> 3); \ + if (ptr > sizeof sc->data) \ + break; \ + num --; \ + } \ + \ + state_read; \ + if (num >= 13) { \ + blank13; \ + num -= 13; \ + } \ + while (num -- > 0) \ + blank1; \ + \ + num = 0; \ + out = dst; \ + for (;;) { \ + OUTW(out, a1); \ + out += width >> 3; \ + OUTW(out, a2); \ + out += width >> 3; \ + num += 2 * (width >> 3); \ + if (num >= 32) \ + break; \ + blank1; \ + } \ + INIT; \ + } while (0) + +/* + * Initialize context structure. + */ +#if SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN + +#define INIT do { \ + memset(sc->a, 0, sizeof sc->a); \ + memset(sc->b, 0, sizeof sc->b); \ + sc->data_ptr = 0; \ + } while (0) + +#else + +#define INIT do { \ + size_t u; \ + for (u = 0; u < 19; u ++) \ + sc->a[u] = 0; \ + for (u = 0; u < 39; u ++) \ + sc->b[u] = 0; \ + sc->data_ptr = 0; \ + } while (0) + +#endif + +/* ======================================================================= */ +/* + * RadioGatun[32]. + */ + +#if !SPH_NO_RG32 + +#undef WT +#define WT sph_u32 +#undef T +#define T SPH_T32 +#undef ROR +#define ROR(x, n) SPH_T32(((x) << ((32 - (n)) & 31)) | ((x) >> ((n) & 31))) +#undef INW +#define INW(i, j) sph_dec32le_aligned(buf + (4 * (3 * (i) + (j)))) +#undef OUTW +#define OUTW(b, v) sph_enc32le(b, v) + +/* + * Insert data by big chunks of 13*12 = 156 bytes. Returned value is the + * number of remaining bytes (between 0 and 155). This method assumes that + * the input data is suitably aligned. + */ +static size_t +radiogatun32_push13(sph_radiogatun32_context *sc, const void *data, size_t len) +{ + PUSH13; +} + +/* see sph_radiogatun.h */ +void +sph_radiogatun32_init(void *cc) +{ + sph_radiogatun32_context *sc; + + sc = cc; + INIT; +} + +#ifdef SPH_UPTR +static void +radiogatun32_short(void *cc, const void *data, size_t len) +#else +/* see sph_radiogatun.h */ +void +sph_radiogatun32(void *cc, const void *data, size_t len) +#endif +{ + sph_radiogatun32_context *sc; + unsigned ptr; + + sc = cc; + ptr = sc->data_ptr; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->data) - ptr; + if (clen > len) + clen = len; + memcpy(sc->data + ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + ptr += clen; + if (ptr == sizeof sc->data) { + radiogatun32_push13(sc, sc->data, sizeof sc->data); + ptr = 0; + } + } + sc->data_ptr = ptr; +} + +#ifdef SPH_UPTR +/* see sph_radiogatun.h */ +void +sph_radiogatun32(void *cc, const void *data, size_t len) +{ + sph_radiogatun32_context *sc; + unsigned ptr; + size_t rlen; + + if (len < (2 * sizeof sc->data)) { + radiogatun32_short(cc, data, len); + return; + } + sc = cc; + ptr = sc->data_ptr; + if (ptr > 0) { + unsigned t; + + t = (sizeof sc->data) - ptr; + radiogatun32_short(sc, data, t); + data = (const unsigned char *)data + t; + len -= t; + } +#if !SPH_UNALIGNED + if (((SPH_UPTR)data & 3) != 0) { + radiogatun32_short(sc, data, len); + return; + } +#endif + rlen = radiogatun32_push13(sc, data, len); + memcpy(sc->data, (const unsigned char *)data + len - rlen, rlen); + sc->data_ptr = rlen; +} +#endif + +/* see sph_radiogatun.h */ +void +sph_radiogatun32_close(void *cc, void *dst) +{ + sph_radiogatun32_context *sc; + + sc = cc; + CLOSE(32); +} + +#endif + +/* ======================================================================= */ +/* + * RadioGatun[64]. Compiled only if a 64-bit or more type is available. + */ + +#if SPH_64 + +#if !SPH_NO_RG64 + +#undef WT +#define WT sph_u64 +#undef T +#define T SPH_T64 +#undef ROR +#define ROR(x, n) SPH_T64(((x) << ((64 - (n)) & 63)) | ((x) >> ((n) & 63))) +#undef INW +#define INW(i, j) sph_dec64le_aligned(buf + (8 * (3 * (i) + (j)))) +#undef OUTW +#define OUTW(b, v) sph_enc64le(b, v) + +/* + * On 32-bit x86, register pressure is such that using the small + * footprint version is a net gain (x2 speed), because that variant + * uses fewer local variables. + */ +#if SPH_I386_MSVC || SPH_I386_GCC || defined __i386__ +#undef PUSH13 +#define PUSH13 PUSH13_SF +#undef CLOSE +#define CLOSE CLOSE_SF +#endif + +/* + * Insert data by big chunks of 13*24 = 312 bytes. Returned value is the + * number of remaining bytes (between 0 and 311). This method assumes that + * the input data is suitably aligned. + */ +static size_t +radiogatun64_push13(sph_radiogatun64_context *sc, const void *data, size_t len) +{ + PUSH13; +} + +/* see sph_radiogatun.h */ +void +sph_radiogatun64_init(void *cc) +{ + sph_radiogatun64_context *sc; + + sc = cc; + INIT; +} + +#ifdef SPH_UPTR +static void +radiogatun64_short(void *cc, const void *data, size_t len) +#else +/* see sph_radiogatun.h */ +void +sph_radiogatun64(void *cc, const void *data, size_t len) +#endif +{ + sph_radiogatun64_context *sc; + unsigned ptr; + + sc = cc; + ptr = sc->data_ptr; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->data) - ptr; + if (clen > len) + clen = len; + memcpy(sc->data + ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + ptr += clen; + if (ptr == sizeof sc->data) { + radiogatun64_push13(sc, sc->data, sizeof sc->data); + ptr = 0; + } + } + sc->data_ptr = ptr; +} + +#ifdef SPH_UPTR +/* see sph_radiogatun.h */ +void +sph_radiogatun64(void *cc, const void *data, size_t len) +{ + sph_radiogatun64_context *sc; + unsigned ptr; + size_t rlen; + + if (len < (2 * sizeof sc->data)) { + radiogatun64_short(cc, data, len); + return; + } + sc = cc; + ptr = sc->data_ptr; + if (ptr > 0) { + unsigned t; + + t = (sizeof sc->data) - ptr; + radiogatun64_short(sc, data, t); + data = (const unsigned char *)data + t; + len -= t; + } +#if !SPH_UNALIGNED + if (((SPH_UPTR)data & 7) != 0) { + radiogatun64_short(sc, data, len); + return; + } +#endif + rlen = radiogatun64_push13(sc, data, len); + memcpy(sc->data, (const unsigned char *)data + len - rlen, rlen); + sc->data_ptr = rlen; +} +#endif + +/* see sph_radiogatun.h */ +void +sph_radiogatun64_close(void *cc, void *dst) +{ + sph_radiogatun64_context *sc; + + sc = cc; + CLOSE(64); +} + +#endif + +#endif diff --git a/sha3/sph_radiogatun.h b/sha3/sph_radiogatun.h new file mode 100644 index 000000000..763839771 --- /dev/null +++ b/sha3/sph_radiogatun.h @@ -0,0 +1,186 @@ +/* $Id: sph_radiogatun.h 226 2010-06-16 17:28:08Z tp $ */ +/** + * RadioGatun interface. + * + * RadioGatun has been published in: G. Bertoni, J. Daemen, M. Peeters + * and G. Van Assche, "RadioGatun, a belt-and-mill hash function", + * presented at the Second Cryptographic Hash Workshop, Santa Barbara, + * August 24-25, 2006. The main Web site, containing that article, the + * reference code and some test vectors, appears to be currently located + * at the following URL: http://radiogatun.noekeon.org/ + * + * The presentation article does not specify endianness or padding. The + * reference code uses the following conventions, which we also apply + * here: + *
      + *
    • The input message is an integral number of sequences of three + * words. Each word is either a 32-bit of 64-bit word (depending on + * the version of RadioGatun).
    • + *
    • Input bytes are decoded into words using little-endian + * convention.
    • + *
    • Padding consists of a single bit of value 1, using little-endian + * convention within bytes (i.e. for a byte-oriented input, a single + * byte of value 0x01 is appended), then enough bits of value 0 to finish + * the current block.
    • + *
    • Output consists of 256 bits. Successive output words are encoded + * with little-endian convention.
    • + *
    + * These conventions are very close to those we use for PANAMA, which is + * a close ancestor or RadioGatun. + * + * RadioGatun is actually a family of functions, depending on some + * internal parameters. We implement here two functions, with a "belt + * length" of 13, a "belt width" of 3, and a "mill length" of 19. The + * RadioGatun[32] version uses 32-bit words, while the RadioGatun[64] + * variant uses 64-bit words. + * + * Strictly speaking, the name "RadioGatun" should use an acute accent + * on the "u", which we omitted here to keep strict ASCII-compatibility + * of this file. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_radiogatun.h + * @author Thomas Pornin + */ + +#ifndef SPH_RADIOGATUN_H__ +#define SPH_RADIOGATUN_H__ + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for RadioGatun[32]. + */ +#define SPH_SIZE_radiogatun32 256 + +/** + * This structure is a context for RadioGatun[32] computations: it + * contains intermediate values and some data from the last entered + * block. Once a RadioGatun[32] computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running RadioGatun[32] + * computation can be cloned by copying the context (e.g. with a + * simple memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char data[156]; /* first field, for alignment */ + unsigned data_ptr; + sph_u32 a[19], b[39]; +#endif +} sph_radiogatun32_context; + +/** + * Initialize a RadioGatun[32] context. This process performs no + * memory allocation. + * + * @param cc the RadioGatun[32] context (pointer to a + * sph_radiogatun32_context) + */ +void sph_radiogatun32_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the RadioGatun[32] context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_radiogatun32(void *cc, const void *data, size_t len); + +/** + * Terminate the current RadioGatun[32] computation and output the + * result into the provided buffer. The destination buffer must be wide + * enough to accomodate the result (32 bytes). The context is + * automatically reinitialized. + * + * @param cc the RadioGatun[32] context + * @param dst the destination buffer + */ +void sph_radiogatun32_close(void *cc, void *dst); + +#if SPH_64 + +/** + * Output size (in bits) for RadioGatun[64]. + */ +#define SPH_SIZE_radiogatun64 256 + +/** + * This structure is a context for RadioGatun[64] computations: it + * contains intermediate values and some data from the last entered + * block. Once a RadioGatun[64] computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running RadioGatun[64] + * computation can be cloned by copying the context (e.g. with a + * simple memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char data[312]; /* first field, for alignment */ + unsigned data_ptr; + sph_u64 a[19], b[39]; +#endif +} sph_radiogatun64_context; + +/** + * Initialize a RadioGatun[64] context. This process performs no + * memory allocation. + * + * @param cc the RadioGatun[64] context (pointer to a + * sph_radiogatun64_context) + */ +void sph_radiogatun64_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the RadioGatun[64] context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_radiogatun64(void *cc, const void *data, size_t len); + +/** + * Terminate the current RadioGatun[64] computation and output the + * result into the provided buffer. The destination buffer must be wide + * enough to accomodate the result (32 bytes). The context is + * automatically reinitialized. + * + * @param cc the RadioGatun[64] context + * @param dst the destination buffer + */ +void sph_radiogatun64_close(void *cc, void *dst); + +#endif + +#endif \ No newline at end of file diff --git a/sha3/sph_ripemd.c b/sha3/sph_ripemd.c new file mode 100644 index 000000000..22c91d0e6 --- /dev/null +++ b/sha3/sph_ripemd.c @@ -0,0 +1,834 @@ +/* $Id: ripemd.c 216 2010-06-08 09:46:57Z tp $ */ +/* + * RIPEMD-160 implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_ripemd.h" + +/* + * Round functions for RIPEMD (original). + */ +#define F(x, y, z) ((((y) ^ (z)) & (x)) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (((x) | (y)) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +static const sph_u32 oIV[5] = { + SPH_C32(0x67452301), SPH_C32(0xEFCDAB89), + SPH_C32(0x98BADCFE), SPH_C32(0x10325476) +}; + +/* + * Round functions for RIPEMD-128 and RIPEMD-160. + */ +#define F1(x, y, z) ((x) ^ (y) ^ (z)) +#define F2(x, y, z) ((((y) ^ (z)) & (x)) ^ (z)) +#define F3(x, y, z) (((x) | ~(y)) ^ (z)) +#define F4(x, y, z) ((((x) ^ (y)) & (z)) ^ (y)) +#define F5(x, y, z) ((x) ^ ((y) | ~(z))) + +static const sph_u32 IV[5] = { + SPH_C32(0x67452301), SPH_C32(0xEFCDAB89), SPH_C32(0x98BADCFE), + SPH_C32(0x10325476), SPH_C32(0xC3D2E1F0) +}; + +#define ROTL SPH_ROTL32 + +/* ===================================================================== */ +/* + * RIPEMD (original hash, deprecated). + */ + +#define FF1(A, B, C, D, X, s) do { \ + sph_u32 tmp = SPH_T32((A) + F(B, C, D) + (X)); \ + (A) = ROTL(tmp, (s)); \ + } while (0) + +#define GG1(A, B, C, D, X, s) do { \ + sph_u32 tmp = SPH_T32((A) + G(B, C, D) \ + + (X) + SPH_C32(0x5A827999)); \ + (A) = ROTL(tmp, (s)); \ + } while (0) + +#define HH1(A, B, C, D, X, s) do { \ + sph_u32 tmp = SPH_T32((A) + H(B, C, D) \ + + (X) + SPH_C32(0x6ED9EBA1)); \ + (A) = ROTL(tmp, (s)); \ + } while (0) + +#define FF2(A, B, C, D, X, s) do { \ + sph_u32 tmp = SPH_T32((A) + F(B, C, D) \ + + (X) + SPH_C32(0x50A28BE6)); \ + (A) = ROTL(tmp, (s)); \ + } while (0) + +#define GG2(A, B, C, D, X, s) do { \ + sph_u32 tmp = SPH_T32((A) + G(B, C, D) + (X)); \ + (A) = ROTL(tmp, (s)); \ + } while (0) + +#define HH2(A, B, C, D, X, s) do { \ + sph_u32 tmp = SPH_T32((A) + H(B, C, D) \ + + (X) + SPH_C32(0x5C4DD124)); \ + (A) = ROTL(tmp, (s)); \ + } while (0) + +#define RIPEMD_ROUND_BODY(in, h) do { \ + sph_u32 A1, B1, C1, D1; \ + sph_u32 A2, B2, C2, D2; \ + sph_u32 tmp; \ + \ + A1 = A2 = (h)[0]; \ + B1 = B2 = (h)[1]; \ + C1 = C2 = (h)[2]; \ + D1 = D2 = (h)[3]; \ + \ + FF1(A1, B1, C1, D1, in( 0), 11); \ + FF1(D1, A1, B1, C1, in( 1), 14); \ + FF1(C1, D1, A1, B1, in( 2), 15); \ + FF1(B1, C1, D1, A1, in( 3), 12); \ + FF1(A1, B1, C1, D1, in( 4), 5); \ + FF1(D1, A1, B1, C1, in( 5), 8); \ + FF1(C1, D1, A1, B1, in( 6), 7); \ + FF1(B1, C1, D1, A1, in( 7), 9); \ + FF1(A1, B1, C1, D1, in( 8), 11); \ + FF1(D1, A1, B1, C1, in( 9), 13); \ + FF1(C1, D1, A1, B1, in(10), 14); \ + FF1(B1, C1, D1, A1, in(11), 15); \ + FF1(A1, B1, C1, D1, in(12), 6); \ + FF1(D1, A1, B1, C1, in(13), 7); \ + FF1(C1, D1, A1, B1, in(14), 9); \ + FF1(B1, C1, D1, A1, in(15), 8); \ + \ + GG1(A1, B1, C1, D1, in( 7), 7); \ + GG1(D1, A1, B1, C1, in( 4), 6); \ + GG1(C1, D1, A1, B1, in(13), 8); \ + GG1(B1, C1, D1, A1, in( 1), 13); \ + GG1(A1, B1, C1, D1, in(10), 11); \ + GG1(D1, A1, B1, C1, in( 6), 9); \ + GG1(C1, D1, A1, B1, in(15), 7); \ + GG1(B1, C1, D1, A1, in( 3), 15); \ + GG1(A1, B1, C1, D1, in(12), 7); \ + GG1(D1, A1, B1, C1, in( 0), 12); \ + GG1(C1, D1, A1, B1, in( 9), 15); \ + GG1(B1, C1, D1, A1, in( 5), 9); \ + GG1(A1, B1, C1, D1, in(14), 7); \ + GG1(D1, A1, B1, C1, in( 2), 11); \ + GG1(C1, D1, A1, B1, in(11), 13); \ + GG1(B1, C1, D1, A1, in( 8), 12); \ + \ + HH1(A1, B1, C1, D1, in( 3), 11); \ + HH1(D1, A1, B1, C1, in(10), 13); \ + HH1(C1, D1, A1, B1, in( 2), 14); \ + HH1(B1, C1, D1, A1, in( 4), 7); \ + HH1(A1, B1, C1, D1, in( 9), 14); \ + HH1(D1, A1, B1, C1, in(15), 9); \ + HH1(C1, D1, A1, B1, in( 8), 13); \ + HH1(B1, C1, D1, A1, in( 1), 15); \ + HH1(A1, B1, C1, D1, in(14), 6); \ + HH1(D1, A1, B1, C1, in( 7), 8); \ + HH1(C1, D1, A1, B1, in( 0), 13); \ + HH1(B1, C1, D1, A1, in( 6), 6); \ + HH1(A1, B1, C1, D1, in(11), 12); \ + HH1(D1, A1, B1, C1, in(13), 5); \ + HH1(C1, D1, A1, B1, in( 5), 7); \ + HH1(B1, C1, D1, A1, in(12), 5); \ + \ + FF2(A2, B2, C2, D2, in( 0), 11); \ + FF2(D2, A2, B2, C2, in( 1), 14); \ + FF2(C2, D2, A2, B2, in( 2), 15); \ + FF2(B2, C2, D2, A2, in( 3), 12); \ + FF2(A2, B2, C2, D2, in( 4), 5); \ + FF2(D2, A2, B2, C2, in( 5), 8); \ + FF2(C2, D2, A2, B2, in( 6), 7); \ + FF2(B2, C2, D2, A2, in( 7), 9); \ + FF2(A2, B2, C2, D2, in( 8), 11); \ + FF2(D2, A2, B2, C2, in( 9), 13); \ + FF2(C2, D2, A2, B2, in(10), 14); \ + FF2(B2, C2, D2, A2, in(11), 15); \ + FF2(A2, B2, C2, D2, in(12), 6); \ + FF2(D2, A2, B2, C2, in(13), 7); \ + FF2(C2, D2, A2, B2, in(14), 9); \ + FF2(B2, C2, D2, A2, in(15), 8); \ + \ + GG2(A2, B2, C2, D2, in( 7), 7); \ + GG2(D2, A2, B2, C2, in( 4), 6); \ + GG2(C2, D2, A2, B2, in(13), 8); \ + GG2(B2, C2, D2, A2, in( 1), 13); \ + GG2(A2, B2, C2, D2, in(10), 11); \ + GG2(D2, A2, B2, C2, in( 6), 9); \ + GG2(C2, D2, A2, B2, in(15), 7); \ + GG2(B2, C2, D2, A2, in( 3), 15); \ + GG2(A2, B2, C2, D2, in(12), 7); \ + GG2(D2, A2, B2, C2, in( 0), 12); \ + GG2(C2, D2, A2, B2, in( 9), 15); \ + GG2(B2, C2, D2, A2, in( 5), 9); \ + GG2(A2, B2, C2, D2, in(14), 7); \ + GG2(D2, A2, B2, C2, in( 2), 11); \ + GG2(C2, D2, A2, B2, in(11), 13); \ + GG2(B2, C2, D2, A2, in( 8), 12); \ + \ + HH2(A2, B2, C2, D2, in( 3), 11); \ + HH2(D2, A2, B2, C2, in(10), 13); \ + HH2(C2, D2, A2, B2, in( 2), 14); \ + HH2(B2, C2, D2, A2, in( 4), 7); \ + HH2(A2, B2, C2, D2, in( 9), 14); \ + HH2(D2, A2, B2, C2, in(15), 9); \ + HH2(C2, D2, A2, B2, in( 8), 13); \ + HH2(B2, C2, D2, A2, in( 1), 15); \ + HH2(A2, B2, C2, D2, in(14), 6); \ + HH2(D2, A2, B2, C2, in( 7), 8); \ + HH2(C2, D2, A2, B2, in( 0), 13); \ + HH2(B2, C2, D2, A2, in( 6), 6); \ + HH2(A2, B2, C2, D2, in(11), 12); \ + HH2(D2, A2, B2, C2, in(13), 5); \ + HH2(C2, D2, A2, B2, in( 5), 7); \ + HH2(B2, C2, D2, A2, in(12), 5); \ + \ + tmp = SPH_T32((h)[1] + C1 + D2); \ + (h)[1] = SPH_T32((h)[2] + D1 + A2); \ + (h)[2] = SPH_T32((h)[3] + A1 + B2); \ + (h)[3] = SPH_T32((h)[0] + B1 + C2); \ + (h)[0] = tmp; \ + } while (0) + +/* + * One round of RIPEMD. The data must be aligned for 32-bit access. + */ +static void +ripemd_round(const unsigned char *data, sph_u32 r[5]) +{ +#if SPH_LITTLE_FAST + +#define RIPEMD_IN(x) sph_dec32le_aligned(data + (4 * (x))) + +#else + + sph_u32 X_var[16]; + int i; + + for (i = 0; i < 16; i ++) + X_var[i] = sph_dec32le_aligned(data + 4 * i); +#define RIPEMD_IN(x) X_var[x] + +#endif + RIPEMD_ROUND_BODY(RIPEMD_IN, r); +#undef RIPEMD_IN +} + +/* see sph_ripemd.h */ +void +sph_ripemd_init(void *cc) +{ + sph_ripemd_context *sc; + + sc = (sph_ripemd_context*)cc; + memcpy(sc->val, oIV, sizeof sc->val); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +#define RFUN ripemd_round +#define HASH ripemd +#define LE32 1 +#include "md_helper.c" +#undef RFUN +#undef HASH +#undef LE32 + +/* see sph_ripemd.h */ +void +sph_ripemd_close(void *cc, void *dst) +{ + ripemd_close(cc, dst, 4); + sph_ripemd_init(cc); +} + +/* see sph_ripemd.h */ +void +sph_ripemd_comp(const sph_u32 msg[16], sph_u32 val[4]) +{ +#define RIPEMD_IN(x) msg[x] + RIPEMD_ROUND_BODY(RIPEMD_IN, val); +#undef RIPEMD_IN +} + +/* ===================================================================== */ +/* + * RIPEMD-128. + */ + +/* + * Round constants for RIPEMD-128. + */ +#define sK11 SPH_C32(0x00000000) +#define sK12 SPH_C32(0x5A827999) +#define sK13 SPH_C32(0x6ED9EBA1) +#define sK14 SPH_C32(0x8F1BBCDC) + +#define sK21 SPH_C32(0x50A28BE6) +#define sK22 SPH_C32(0x5C4DD124) +#define sK23 SPH_C32(0x6D703EF3) +#define sK24 SPH_C32(0x00000000) + +#define sRR(a, b, c, d, f, s, r, k) do { \ + a = ROTL(SPH_T32(a + f(b, c, d) + r + k), s); \ + } while (0) + +#define sROUND1(a, b, c, d, f, s, r, k) \ + sRR(a ## 1, b ## 1, c ## 1, d ## 1, f, s, r, sK1 ## k) + +#define sROUND2(a, b, c, d, f, s, r, k) \ + sRR(a ## 2, b ## 2, c ## 2, d ## 2, f, s, r, sK2 ## k) + +/* + * This macro defines the body for a RIPEMD-128 compression function + * implementation. The "in" parameter should evaluate, when applied to a + * numerical input parameter from 0 to 15, to an expression which yields + * the corresponding input block. The "h" parameter should evaluate to + * an array or pointer expression designating the array of 4 words which + * contains the input and output of the compression function. + */ + +#define RIPEMD128_ROUND_BODY(in, h) do { \ + sph_u32 A1, B1, C1, D1; \ + sph_u32 A2, B2, C2, D2; \ + sph_u32 tmp; \ + \ + A1 = A2 = (h)[0]; \ + B1 = B2 = (h)[1]; \ + C1 = C2 = (h)[2]; \ + D1 = D2 = (h)[3]; \ + \ + sROUND1(A, B, C, D, F1, 11, in( 0), 1); \ + sROUND1(D, A, B, C, F1, 14, in( 1), 1); \ + sROUND1(C, D, A, B, F1, 15, in( 2), 1); \ + sROUND1(B, C, D, A, F1, 12, in( 3), 1); \ + sROUND1(A, B, C, D, F1, 5, in( 4), 1); \ + sROUND1(D, A, B, C, F1, 8, in( 5), 1); \ + sROUND1(C, D, A, B, F1, 7, in( 6), 1); \ + sROUND1(B, C, D, A, F1, 9, in( 7), 1); \ + sROUND1(A, B, C, D, F1, 11, in( 8), 1); \ + sROUND1(D, A, B, C, F1, 13, in( 9), 1); \ + sROUND1(C, D, A, B, F1, 14, in(10), 1); \ + sROUND1(B, C, D, A, F1, 15, in(11), 1); \ + sROUND1(A, B, C, D, F1, 6, in(12), 1); \ + sROUND1(D, A, B, C, F1, 7, in(13), 1); \ + sROUND1(C, D, A, B, F1, 9, in(14), 1); \ + sROUND1(B, C, D, A, F1, 8, in(15), 1); \ + \ + sROUND1(A, B, C, D, F2, 7, in( 7), 2); \ + sROUND1(D, A, B, C, F2, 6, in( 4), 2); \ + sROUND1(C, D, A, B, F2, 8, in(13), 2); \ + sROUND1(B, C, D, A, F2, 13, in( 1), 2); \ + sROUND1(A, B, C, D, F2, 11, in(10), 2); \ + sROUND1(D, A, B, C, F2, 9, in( 6), 2); \ + sROUND1(C, D, A, B, F2, 7, in(15), 2); \ + sROUND1(B, C, D, A, F2, 15, in( 3), 2); \ + sROUND1(A, B, C, D, F2, 7, in(12), 2); \ + sROUND1(D, A, B, C, F2, 12, in( 0), 2); \ + sROUND1(C, D, A, B, F2, 15, in( 9), 2); \ + sROUND1(B, C, D, A, F2, 9, in( 5), 2); \ + sROUND1(A, B, C, D, F2, 11, in( 2), 2); \ + sROUND1(D, A, B, C, F2, 7, in(14), 2); \ + sROUND1(C, D, A, B, F2, 13, in(11), 2); \ + sROUND1(B, C, D, A, F2, 12, in( 8), 2); \ + \ + sROUND1(A, B, C, D, F3, 11, in( 3), 3); \ + sROUND1(D, A, B, C, F3, 13, in(10), 3); \ + sROUND1(C, D, A, B, F3, 6, in(14), 3); \ + sROUND1(B, C, D, A, F3, 7, in( 4), 3); \ + sROUND1(A, B, C, D, F3, 14, in( 9), 3); \ + sROUND1(D, A, B, C, F3, 9, in(15), 3); \ + sROUND1(C, D, A, B, F3, 13, in( 8), 3); \ + sROUND1(B, C, D, A, F3, 15, in( 1), 3); \ + sROUND1(A, B, C, D, F3, 14, in( 2), 3); \ + sROUND1(D, A, B, C, F3, 8, in( 7), 3); \ + sROUND1(C, D, A, B, F3, 13, in( 0), 3); \ + sROUND1(B, C, D, A, F3, 6, in( 6), 3); \ + sROUND1(A, B, C, D, F3, 5, in(13), 3); \ + sROUND1(D, A, B, C, F3, 12, in(11), 3); \ + sROUND1(C, D, A, B, F3, 7, in( 5), 3); \ + sROUND1(B, C, D, A, F3, 5, in(12), 3); \ + \ + sROUND1(A, B, C, D, F4, 11, in( 1), 4); \ + sROUND1(D, A, B, C, F4, 12, in( 9), 4); \ + sROUND1(C, D, A, B, F4, 14, in(11), 4); \ + sROUND1(B, C, D, A, F4, 15, in(10), 4); \ + sROUND1(A, B, C, D, F4, 14, in( 0), 4); \ + sROUND1(D, A, B, C, F4, 15, in( 8), 4); \ + sROUND1(C, D, A, B, F4, 9, in(12), 4); \ + sROUND1(B, C, D, A, F4, 8, in( 4), 4); \ + sROUND1(A, B, C, D, F4, 9, in(13), 4); \ + sROUND1(D, A, B, C, F4, 14, in( 3), 4); \ + sROUND1(C, D, A, B, F4, 5, in( 7), 4); \ + sROUND1(B, C, D, A, F4, 6, in(15), 4); \ + sROUND1(A, B, C, D, F4, 8, in(14), 4); \ + sROUND1(D, A, B, C, F4, 6, in( 5), 4); \ + sROUND1(C, D, A, B, F4, 5, in( 6), 4); \ + sROUND1(B, C, D, A, F4, 12, in( 2), 4); \ + \ + sROUND2(A, B, C, D, F4, 8, in( 5), 1); \ + sROUND2(D, A, B, C, F4, 9, in(14), 1); \ + sROUND2(C, D, A, B, F4, 9, in( 7), 1); \ + sROUND2(B, C, D, A, F4, 11, in( 0), 1); \ + sROUND2(A, B, C, D, F4, 13, in( 9), 1); \ + sROUND2(D, A, B, C, F4, 15, in( 2), 1); \ + sROUND2(C, D, A, B, F4, 15, in(11), 1); \ + sROUND2(B, C, D, A, F4, 5, in( 4), 1); \ + sROUND2(A, B, C, D, F4, 7, in(13), 1); \ + sROUND2(D, A, B, C, F4, 7, in( 6), 1); \ + sROUND2(C, D, A, B, F4, 8, in(15), 1); \ + sROUND2(B, C, D, A, F4, 11, in( 8), 1); \ + sROUND2(A, B, C, D, F4, 14, in( 1), 1); \ + sROUND2(D, A, B, C, F4, 14, in(10), 1); \ + sROUND2(C, D, A, B, F4, 12, in( 3), 1); \ + sROUND2(B, C, D, A, F4, 6, in(12), 1); \ + \ + sROUND2(A, B, C, D, F3, 9, in( 6), 2); \ + sROUND2(D, A, B, C, F3, 13, in(11), 2); \ + sROUND2(C, D, A, B, F3, 15, in( 3), 2); \ + sROUND2(B, C, D, A, F3, 7, in( 7), 2); \ + sROUND2(A, B, C, D, F3, 12, in( 0), 2); \ + sROUND2(D, A, B, C, F3, 8, in(13), 2); \ + sROUND2(C, D, A, B, F3, 9, in( 5), 2); \ + sROUND2(B, C, D, A, F3, 11, in(10), 2); \ + sROUND2(A, B, C, D, F3, 7, in(14), 2); \ + sROUND2(D, A, B, C, F3, 7, in(15), 2); \ + sROUND2(C, D, A, B, F3, 12, in( 8), 2); \ + sROUND2(B, C, D, A, F3, 7, in(12), 2); \ + sROUND2(A, B, C, D, F3, 6, in( 4), 2); \ + sROUND2(D, A, B, C, F3, 15, in( 9), 2); \ + sROUND2(C, D, A, B, F3, 13, in( 1), 2); \ + sROUND2(B, C, D, A, F3, 11, in( 2), 2); \ + \ + sROUND2(A, B, C, D, F2, 9, in(15), 3); \ + sROUND2(D, A, B, C, F2, 7, in( 5), 3); \ + sROUND2(C, D, A, B, F2, 15, in( 1), 3); \ + sROUND2(B, C, D, A, F2, 11, in( 3), 3); \ + sROUND2(A, B, C, D, F2, 8, in( 7), 3); \ + sROUND2(D, A, B, C, F2, 6, in(14), 3); \ + sROUND2(C, D, A, B, F2, 6, in( 6), 3); \ + sROUND2(B, C, D, A, F2, 14, in( 9), 3); \ + sROUND2(A, B, C, D, F2, 12, in(11), 3); \ + sROUND2(D, A, B, C, F2, 13, in( 8), 3); \ + sROUND2(C, D, A, B, F2, 5, in(12), 3); \ + sROUND2(B, C, D, A, F2, 14, in( 2), 3); \ + sROUND2(A, B, C, D, F2, 13, in(10), 3); \ + sROUND2(D, A, B, C, F2, 13, in( 0), 3); \ + sROUND2(C, D, A, B, F2, 7, in( 4), 3); \ + sROUND2(B, C, D, A, F2, 5, in(13), 3); \ + \ + sROUND2(A, B, C, D, F1, 15, in( 8), 4); \ + sROUND2(D, A, B, C, F1, 5, in( 6), 4); \ + sROUND2(C, D, A, B, F1, 8, in( 4), 4); \ + sROUND2(B, C, D, A, F1, 11, in( 1), 4); \ + sROUND2(A, B, C, D, F1, 14, in( 3), 4); \ + sROUND2(D, A, B, C, F1, 14, in(11), 4); \ + sROUND2(C, D, A, B, F1, 6, in(15), 4); \ + sROUND2(B, C, D, A, F1, 14, in( 0), 4); \ + sROUND2(A, B, C, D, F1, 6, in( 5), 4); \ + sROUND2(D, A, B, C, F1, 9, in(12), 4); \ + sROUND2(C, D, A, B, F1, 12, in( 2), 4); \ + sROUND2(B, C, D, A, F1, 9, in(13), 4); \ + sROUND2(A, B, C, D, F1, 12, in( 9), 4); \ + sROUND2(D, A, B, C, F1, 5, in( 7), 4); \ + sROUND2(C, D, A, B, F1, 15, in(10), 4); \ + sROUND2(B, C, D, A, F1, 8, in(14), 4); \ + \ + tmp = SPH_T32((h)[1] + C1 + D2); \ + (h)[1] = SPH_T32((h)[2] + D1 + A2); \ + (h)[2] = SPH_T32((h)[3] + A1 + B2); \ + (h)[3] = SPH_T32((h)[0] + B1 + C2); \ + (h)[0] = tmp; \ + } while (0) + +/* + * One round of RIPEMD-128. The data must be aligned for 32-bit access. + */ +static void +ripemd128_round(const unsigned char *data, sph_u32 r[5]) +{ +#if SPH_LITTLE_FAST + +#define RIPEMD128_IN(x) sph_dec32le_aligned(data + (4 * (x))) + +#else + + sph_u32 X_var[16]; + int i; + + for (i = 0; i < 16; i ++) + X_var[i] = sph_dec32le_aligned(data + 4 * i); +#define RIPEMD128_IN(x) X_var[x] + +#endif + RIPEMD128_ROUND_BODY(RIPEMD128_IN, r); +#undef RIPEMD128_IN +} + +/* see sph_ripemd.h */ +void +sph_ripemd128_init(void *cc) +{ + sph_ripemd128_context *sc; + + sc = (sph_ripemd128_context*)cc; + memcpy(sc->val, IV, sizeof sc->val); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +#define RFUN ripemd128_round +#define HASH ripemd128 +#define LE32 1 +#include "md_helper.c" +#undef RFUN +#undef HASH +#undef LE32 + +/* see sph_ripemd.h */ +void +sph_ripemd128_close(void *cc, void *dst) +{ + ripemd128_close(cc, dst, 4); + sph_ripemd128_init(cc); +} + +/* see sph_ripemd.h */ +void +sph_ripemd128_comp(const sph_u32 msg[16], sph_u32 val[4]) +{ +#define RIPEMD128_IN(x) msg[x] + RIPEMD128_ROUND_BODY(RIPEMD128_IN, val); +#undef RIPEMD128_IN +} + +/* ===================================================================== */ +/* + * RIPEMD-160. + */ + +/* + * Round constants for RIPEMD-160. + */ +#define K11 SPH_C32(0x00000000) +#define K12 SPH_C32(0x5A827999) +#define K13 SPH_C32(0x6ED9EBA1) +#define K14 SPH_C32(0x8F1BBCDC) +#define K15 SPH_C32(0xA953FD4E) + +#define K21 SPH_C32(0x50A28BE6) +#define K22 SPH_C32(0x5C4DD124) +#define K23 SPH_C32(0x6D703EF3) +#define K24 SPH_C32(0x7A6D76E9) +#define K25 SPH_C32(0x00000000) + +#define RR(a, b, c, d, e, f, s, r, k) do { \ + a = SPH_T32(ROTL(SPH_T32(a + f(b, c, d) + r + k), s) + e); \ + c = ROTL(c, 10); \ + } while (0) + +#define ROUND1(a, b, c, d, e, f, s, r, k) \ + RR(a ## 1, b ## 1, c ## 1, d ## 1, e ## 1, f, s, r, K1 ## k) + +#define ROUND2(a, b, c, d, e, f, s, r, k) \ + RR(a ## 2, b ## 2, c ## 2, d ## 2, e ## 2, f, s, r, K2 ## k) + +/* + * This macro defines the body for a RIPEMD-160 compression function + * implementation. The "in" parameter should evaluate, when applied to a + * numerical input parameter from 0 to 15, to an expression which yields + * the corresponding input block. The "h" parameter should evaluate to + * an array or pointer expression designating the array of 5 words which + * contains the input and output of the compression function. + */ + +#define RIPEMD160_ROUND_BODY(in, h) do { \ + sph_u32 A1, B1, C1, D1, E1; \ + sph_u32 A2, B2, C2, D2, E2; \ + sph_u32 tmp; \ + \ + A1 = A2 = (h)[0]; \ + B1 = B2 = (h)[1]; \ + C1 = C2 = (h)[2]; \ + D1 = D2 = (h)[3]; \ + E1 = E2 = (h)[4]; \ + \ + ROUND1(A, B, C, D, E, F1, 11, in( 0), 1); \ + ROUND1(E, A, B, C, D, F1, 14, in( 1), 1); \ + ROUND1(D, E, A, B, C, F1, 15, in( 2), 1); \ + ROUND1(C, D, E, A, B, F1, 12, in( 3), 1); \ + ROUND1(B, C, D, E, A, F1, 5, in( 4), 1); \ + ROUND1(A, B, C, D, E, F1, 8, in( 5), 1); \ + ROUND1(E, A, B, C, D, F1, 7, in( 6), 1); \ + ROUND1(D, E, A, B, C, F1, 9, in( 7), 1); \ + ROUND1(C, D, E, A, B, F1, 11, in( 8), 1); \ + ROUND1(B, C, D, E, A, F1, 13, in( 9), 1); \ + ROUND1(A, B, C, D, E, F1, 14, in(10), 1); \ + ROUND1(E, A, B, C, D, F1, 15, in(11), 1); \ + ROUND1(D, E, A, B, C, F1, 6, in(12), 1); \ + ROUND1(C, D, E, A, B, F1, 7, in(13), 1); \ + ROUND1(B, C, D, E, A, F1, 9, in(14), 1); \ + ROUND1(A, B, C, D, E, F1, 8, in(15), 1); \ + \ + ROUND1(E, A, B, C, D, F2, 7, in( 7), 2); \ + ROUND1(D, E, A, B, C, F2, 6, in( 4), 2); \ + ROUND1(C, D, E, A, B, F2, 8, in(13), 2); \ + ROUND1(B, C, D, E, A, F2, 13, in( 1), 2); \ + ROUND1(A, B, C, D, E, F2, 11, in(10), 2); \ + ROUND1(E, A, B, C, D, F2, 9, in( 6), 2); \ + ROUND1(D, E, A, B, C, F2, 7, in(15), 2); \ + ROUND1(C, D, E, A, B, F2, 15, in( 3), 2); \ + ROUND1(B, C, D, E, A, F2, 7, in(12), 2); \ + ROUND1(A, B, C, D, E, F2, 12, in( 0), 2); \ + ROUND1(E, A, B, C, D, F2, 15, in( 9), 2); \ + ROUND1(D, E, A, B, C, F2, 9, in( 5), 2); \ + ROUND1(C, D, E, A, B, F2, 11, in( 2), 2); \ + ROUND1(B, C, D, E, A, F2, 7, in(14), 2); \ + ROUND1(A, B, C, D, E, F2, 13, in(11), 2); \ + ROUND1(E, A, B, C, D, F2, 12, in( 8), 2); \ + \ + ROUND1(D, E, A, B, C, F3, 11, in( 3), 3); \ + ROUND1(C, D, E, A, B, F3, 13, in(10), 3); \ + ROUND1(B, C, D, E, A, F3, 6, in(14), 3); \ + ROUND1(A, B, C, D, E, F3, 7, in( 4), 3); \ + ROUND1(E, A, B, C, D, F3, 14, in( 9), 3); \ + ROUND1(D, E, A, B, C, F3, 9, in(15), 3); \ + ROUND1(C, D, E, A, B, F3, 13, in( 8), 3); \ + ROUND1(B, C, D, E, A, F3, 15, in( 1), 3); \ + ROUND1(A, B, C, D, E, F3, 14, in( 2), 3); \ + ROUND1(E, A, B, C, D, F3, 8, in( 7), 3); \ + ROUND1(D, E, A, B, C, F3, 13, in( 0), 3); \ + ROUND1(C, D, E, A, B, F3, 6, in( 6), 3); \ + ROUND1(B, C, D, E, A, F3, 5, in(13), 3); \ + ROUND1(A, B, C, D, E, F3, 12, in(11), 3); \ + ROUND1(E, A, B, C, D, F3, 7, in( 5), 3); \ + ROUND1(D, E, A, B, C, F3, 5, in(12), 3); \ + \ + ROUND1(C, D, E, A, B, F4, 11, in( 1), 4); \ + ROUND1(B, C, D, E, A, F4, 12, in( 9), 4); \ + ROUND1(A, B, C, D, E, F4, 14, in(11), 4); \ + ROUND1(E, A, B, C, D, F4, 15, in(10), 4); \ + ROUND1(D, E, A, B, C, F4, 14, in( 0), 4); \ + ROUND1(C, D, E, A, B, F4, 15, in( 8), 4); \ + ROUND1(B, C, D, E, A, F4, 9, in(12), 4); \ + ROUND1(A, B, C, D, E, F4, 8, in( 4), 4); \ + ROUND1(E, A, B, C, D, F4, 9, in(13), 4); \ + ROUND1(D, E, A, B, C, F4, 14, in( 3), 4); \ + ROUND1(C, D, E, A, B, F4, 5, in( 7), 4); \ + ROUND1(B, C, D, E, A, F4, 6, in(15), 4); \ + ROUND1(A, B, C, D, E, F4, 8, in(14), 4); \ + ROUND1(E, A, B, C, D, F4, 6, in( 5), 4); \ + ROUND1(D, E, A, B, C, F4, 5, in( 6), 4); \ + ROUND1(C, D, E, A, B, F4, 12, in( 2), 4); \ + \ + ROUND1(B, C, D, E, A, F5, 9, in( 4), 5); \ + ROUND1(A, B, C, D, E, F5, 15, in( 0), 5); \ + ROUND1(E, A, B, C, D, F5, 5, in( 5), 5); \ + ROUND1(D, E, A, B, C, F5, 11, in( 9), 5); \ + ROUND1(C, D, E, A, B, F5, 6, in( 7), 5); \ + ROUND1(B, C, D, E, A, F5, 8, in(12), 5); \ + ROUND1(A, B, C, D, E, F5, 13, in( 2), 5); \ + ROUND1(E, A, B, C, D, F5, 12, in(10), 5); \ + ROUND1(D, E, A, B, C, F5, 5, in(14), 5); \ + ROUND1(C, D, E, A, B, F5, 12, in( 1), 5); \ + ROUND1(B, C, D, E, A, F5, 13, in( 3), 5); \ + ROUND1(A, B, C, D, E, F5, 14, in( 8), 5); \ + ROUND1(E, A, B, C, D, F5, 11, in(11), 5); \ + ROUND1(D, E, A, B, C, F5, 8, in( 6), 5); \ + ROUND1(C, D, E, A, B, F5, 5, in(15), 5); \ + ROUND1(B, C, D, E, A, F5, 6, in(13), 5); \ + \ + ROUND2(A, B, C, D, E, F5, 8, in( 5), 1); \ + ROUND2(E, A, B, C, D, F5, 9, in(14), 1); \ + ROUND2(D, E, A, B, C, F5, 9, in( 7), 1); \ + ROUND2(C, D, E, A, B, F5, 11, in( 0), 1); \ + ROUND2(B, C, D, E, A, F5, 13, in( 9), 1); \ + ROUND2(A, B, C, D, E, F5, 15, in( 2), 1); \ + ROUND2(E, A, B, C, D, F5, 15, in(11), 1); \ + ROUND2(D, E, A, B, C, F5, 5, in( 4), 1); \ + ROUND2(C, D, E, A, B, F5, 7, in(13), 1); \ + ROUND2(B, C, D, E, A, F5, 7, in( 6), 1); \ + ROUND2(A, B, C, D, E, F5, 8, in(15), 1); \ + ROUND2(E, A, B, C, D, F5, 11, in( 8), 1); \ + ROUND2(D, E, A, B, C, F5, 14, in( 1), 1); \ + ROUND2(C, D, E, A, B, F5, 14, in(10), 1); \ + ROUND2(B, C, D, E, A, F5, 12, in( 3), 1); \ + ROUND2(A, B, C, D, E, F5, 6, in(12), 1); \ + \ + ROUND2(E, A, B, C, D, F4, 9, in( 6), 2); \ + ROUND2(D, E, A, B, C, F4, 13, in(11), 2); \ + ROUND2(C, D, E, A, B, F4, 15, in( 3), 2); \ + ROUND2(B, C, D, E, A, F4, 7, in( 7), 2); \ + ROUND2(A, B, C, D, E, F4, 12, in( 0), 2); \ + ROUND2(E, A, B, C, D, F4, 8, in(13), 2); \ + ROUND2(D, E, A, B, C, F4, 9, in( 5), 2); \ + ROUND2(C, D, E, A, B, F4, 11, in(10), 2); \ + ROUND2(B, C, D, E, A, F4, 7, in(14), 2); \ + ROUND2(A, B, C, D, E, F4, 7, in(15), 2); \ + ROUND2(E, A, B, C, D, F4, 12, in( 8), 2); \ + ROUND2(D, E, A, B, C, F4, 7, in(12), 2); \ + ROUND2(C, D, E, A, B, F4, 6, in( 4), 2); \ + ROUND2(B, C, D, E, A, F4, 15, in( 9), 2); \ + ROUND2(A, B, C, D, E, F4, 13, in( 1), 2); \ + ROUND2(E, A, B, C, D, F4, 11, in( 2), 2); \ + \ + ROUND2(D, E, A, B, C, F3, 9, in(15), 3); \ + ROUND2(C, D, E, A, B, F3, 7, in( 5), 3); \ + ROUND2(B, C, D, E, A, F3, 15, in( 1), 3); \ + ROUND2(A, B, C, D, E, F3, 11, in( 3), 3); \ + ROUND2(E, A, B, C, D, F3, 8, in( 7), 3); \ + ROUND2(D, E, A, B, C, F3, 6, in(14), 3); \ + ROUND2(C, D, E, A, B, F3, 6, in( 6), 3); \ + ROUND2(B, C, D, E, A, F3, 14, in( 9), 3); \ + ROUND2(A, B, C, D, E, F3, 12, in(11), 3); \ + ROUND2(E, A, B, C, D, F3, 13, in( 8), 3); \ + ROUND2(D, E, A, B, C, F3, 5, in(12), 3); \ + ROUND2(C, D, E, A, B, F3, 14, in( 2), 3); \ + ROUND2(B, C, D, E, A, F3, 13, in(10), 3); \ + ROUND2(A, B, C, D, E, F3, 13, in( 0), 3); \ + ROUND2(E, A, B, C, D, F3, 7, in( 4), 3); \ + ROUND2(D, E, A, B, C, F3, 5, in(13), 3); \ + \ + ROUND2(C, D, E, A, B, F2, 15, in( 8), 4); \ + ROUND2(B, C, D, E, A, F2, 5, in( 6), 4); \ + ROUND2(A, B, C, D, E, F2, 8, in( 4), 4); \ + ROUND2(E, A, B, C, D, F2, 11, in( 1), 4); \ + ROUND2(D, E, A, B, C, F2, 14, in( 3), 4); \ + ROUND2(C, D, E, A, B, F2, 14, in(11), 4); \ + ROUND2(B, C, D, E, A, F2, 6, in(15), 4); \ + ROUND2(A, B, C, D, E, F2, 14, in( 0), 4); \ + ROUND2(E, A, B, C, D, F2, 6, in( 5), 4); \ + ROUND2(D, E, A, B, C, F2, 9, in(12), 4); \ + ROUND2(C, D, E, A, B, F2, 12, in( 2), 4); \ + ROUND2(B, C, D, E, A, F2, 9, in(13), 4); \ + ROUND2(A, B, C, D, E, F2, 12, in( 9), 4); \ + ROUND2(E, A, B, C, D, F2, 5, in( 7), 4); \ + ROUND2(D, E, A, B, C, F2, 15, in(10), 4); \ + ROUND2(C, D, E, A, B, F2, 8, in(14), 4); \ + \ + ROUND2(B, C, D, E, A, F1, 8, in(12), 5); \ + ROUND2(A, B, C, D, E, F1, 5, in(15), 5); \ + ROUND2(E, A, B, C, D, F1, 12, in(10), 5); \ + ROUND2(D, E, A, B, C, F1, 9, in( 4), 5); \ + ROUND2(C, D, E, A, B, F1, 12, in( 1), 5); \ + ROUND2(B, C, D, E, A, F1, 5, in( 5), 5); \ + ROUND2(A, B, C, D, E, F1, 14, in( 8), 5); \ + ROUND2(E, A, B, C, D, F1, 6, in( 7), 5); \ + ROUND2(D, E, A, B, C, F1, 8, in( 6), 5); \ + ROUND2(C, D, E, A, B, F1, 13, in( 2), 5); \ + ROUND2(B, C, D, E, A, F1, 6, in(13), 5); \ + ROUND2(A, B, C, D, E, F1, 5, in(14), 5); \ + ROUND2(E, A, B, C, D, F1, 15, in( 0), 5); \ + ROUND2(D, E, A, B, C, F1, 13, in( 3), 5); \ + ROUND2(C, D, E, A, B, F1, 11, in( 9), 5); \ + ROUND2(B, C, D, E, A, F1, 11, in(11), 5); \ + \ + tmp = SPH_T32((h)[1] + C1 + D2); \ + (h)[1] = SPH_T32((h)[2] + D1 + E2); \ + (h)[2] = SPH_T32((h)[3] + E1 + A2); \ + (h)[3] = SPH_T32((h)[4] + A1 + B2); \ + (h)[4] = SPH_T32((h)[0] + B1 + C2); \ + (h)[0] = tmp; \ + } while (0) + +/* + * One round of RIPEMD-160. The data must be aligned for 32-bit access. + */ +static void +ripemd160_round(const unsigned char *data, sph_u32 r[5]) +{ +#if SPH_LITTLE_FAST + +#define RIPEMD160_IN(x) sph_dec32le_aligned(data + (4 * (x))) + +#else + + sph_u32 X_var[16]; + int i; + + for (i = 0; i < 16; i ++) + X_var[i] = sph_dec32le_aligned(data + 4 * i); +#define RIPEMD160_IN(x) X_var[x] + +#endif + RIPEMD160_ROUND_BODY(RIPEMD160_IN, r); +#undef RIPEMD160_IN +} + +/* see sph_ripemd.h */ +void +sph_ripemd160_init(void *cc) +{ + sph_ripemd160_context *sc; + + sc = (sph_ripemd160_context*)cc; + memcpy(sc->val, IV, sizeof sc->val); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +#define RFUN ripemd160_round +#define HASH ripemd160 +#define LE32 1 +#include "md_helper.c" +#undef RFUN +#undef HASH +#undef LE32 + +/* see sph_ripemd.h */ +void +sph_ripemd160_close(void *cc, void *dst) +{ + ripemd160_close(cc, dst, 5); + sph_ripemd160_init(cc); +} + +/* see sph_ripemd.h */ +void +sph_ripemd160_comp(const sph_u32 msg[16], sph_u32 val[5]) +{ +#define RIPEMD160_IN(x) msg[x] + RIPEMD160_ROUND_BODY(RIPEMD160_IN, val); +#undef RIPEMD160_IN +} + diff --git a/sha3/sph_ripemd.h b/sha3/sph_ripemd.h new file mode 100644 index 000000000..0f938be56 --- /dev/null +++ b/sha3/sph_ripemd.h @@ -0,0 +1,274 @@ +/* $Id: sph_ripemd.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * RIPEMD, RIPEMD-128 and RIPEMD-160 interface. + * + * RIPEMD was first described in: Research and Development in Advanced + * Communication Technologies in Europe, "RIPE Integrity Primitives: + * Final Report of RACE Integrity Primitives Evaluation (R1040)", RACE, + * June 1992. + * + * A new, strengthened version, dubbed RIPEMD-160, was published in: H. + * Dobbertin, A. Bosselaers, and B. Preneel, "RIPEMD-160, a strengthened + * version of RIPEMD", Fast Software Encryption - FSE'96, LNCS 1039, + * Springer (1996), pp. 71--82. + * + * This article describes both RIPEMD-160, with a 160-bit output, and a + * reduced version called RIPEMD-128, which has a 128-bit output. RIPEMD-128 + * was meant as a "drop-in" replacement for any hash function with 128-bit + * output, especially the original RIPEMD. + * + * @warning Collisions, and an efficient method to build other collisions, + * have been published for the original RIPEMD, which is thus considered as + * cryptographically broken. It is also very rarely encountered, and there + * seems to exist no free description or implementation of RIPEMD (except + * the sphlib code, of course). As of january 2007, RIPEMD-128 and RIPEMD-160 + * seem as secure as their output length allows. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_ripemd.h + * @author Thomas Pornin + */ + +#ifndef SPH_RIPEMD_H__ +#define SPH_RIPEMD_H__ + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for RIPEMD. + */ +#define SPH_SIZE_ripemd 128 + +/** + * Output size (in bits) for RIPEMD-128. + */ +#define SPH_SIZE_ripemd128 128 + +/** + * Output size (in bits) for RIPEMD-160. + */ +#define SPH_SIZE_ripemd160 160 + +/** + * This structure is a context for RIPEMD computations: it contains the + * intermediate values and some data from the last entered block. Once + * a RIPEMD computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running RIPEMD computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + sph_u32 val[4]; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_ripemd_context; + +/** + * Initialize a RIPEMD context. This process performs no memory allocation. + * + * @param cc the RIPEMD context (pointer to + * a sph_ripemd_context) + */ +void sph_ripemd_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the RIPEMD context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_ripemd(void *cc, const void *data, size_t len); + +/** + * Terminate the current RIPEMD computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (16 bytes). The context is automatically + * reinitialized. + * + * @param cc the RIPEMD context + * @param dst the destination buffer + */ +void sph_ripemd_close(void *cc, void *dst); + +/** + * Apply the RIPEMD compression function on the provided data. The + * msg parameter contains the 16 32-bit input blocks, + * as numerical values (hence after the little-endian decoding). The + * val parameter contains the 5 32-bit input blocks for + * the compression function; the output is written in place in this + * array. + * + * @param msg the message block (16 values) + * @param val the function 128-bit input and output + */ +void sph_ripemd_comp(const sph_u32 msg[16], sph_u32 val[4]); + +/* ===================================================================== */ + +/** + * This structure is a context for RIPEMD-128 computations: it contains the + * intermediate values and some data from the last entered block. Once + * a RIPEMD-128 computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running RIPEMD-128 computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + sph_u32 val[4]; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_ripemd128_context; + +/** + * Initialize a RIPEMD-128 context. This process performs no memory allocation. + * + * @param cc the RIPEMD-128 context (pointer to + * a sph_ripemd128_context) + */ +void sph_ripemd128_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the RIPEMD-128 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_ripemd128(void *cc, const void *data, size_t len); + +/** + * Terminate the current RIPEMD-128 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (16 bytes). The context is automatically + * reinitialized. + * + * @param cc the RIPEMD-128 context + * @param dst the destination buffer + */ +void sph_ripemd128_close(void *cc, void *dst); + +/** + * Apply the RIPEMD-128 compression function on the provided data. The + * msg parameter contains the 16 32-bit input blocks, + * as numerical values (hence after the little-endian decoding). The + * val parameter contains the 5 32-bit input blocks for + * the compression function; the output is written in place in this + * array. + * + * @param msg the message block (16 values) + * @param val the function 128-bit input and output + */ +void sph_ripemd128_comp(const sph_u32 msg[16], sph_u32 val[4]); + +/* ===================================================================== */ + +/** + * This structure is a context for RIPEMD-160 computations: it contains the + * intermediate values and some data from the last entered block. Once + * a RIPEMD-160 computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running RIPEMD-160 computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + sph_u32 val[5]; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_ripemd160_context; + +/** + * Initialize a RIPEMD-160 context. This process performs no memory allocation. + * + * @param cc the RIPEMD-160 context (pointer to + * a sph_ripemd160_context) + */ +void sph_ripemd160_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the RIPEMD-160 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_ripemd160(void *cc, const void *data, size_t len); + +/** + * Terminate the current RIPEMD-160 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (20 bytes). The context is automatically + * reinitialized. + * + * @param cc the RIPEMD-160 context + * @param dst the destination buffer + */ +void sph_ripemd160_close(void *cc, void *dst); + +/** + * Apply the RIPEMD-160 compression function on the provided data. The + * msg parameter contains the 16 32-bit input blocks, + * as numerical values (hence after the little-endian decoding). The + * val parameter contains the 5 32-bit input blocks for + * the compression function; the output is written in place in this + * array. + * + * @param msg the message block (16 values) + * @param val the function 160-bit input and output + */ +void sph_ripemd160_comp(const sph_u32 msg[16], sph_u32 val[5]); + +#endif + diff --git a/sha3/sph_sha2.c b/sha3/sph_sha2.c new file mode 100644 index 000000000..cc8d2902c --- /dev/null +++ b/sha3/sph_sha2.c @@ -0,0 +1,690 @@ +/* $Id: sha2.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * SHA-224 / SHA-256 implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_sha2.h" + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_SHA2 +#define SPH_SMALL_FOOTPRINT_SHA2 1 +#endif + +#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z)) +#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X))) + +#define ROTR SPH_ROTR32 + +#define BSG2_0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define BSG2_1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SSG2_0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SPH_T32((x) >> 3)) +#define SSG2_1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SPH_T32((x) >> 10)) + +static const sph_u32 H224[8] = { + SPH_C32(0xC1059ED8), SPH_C32(0x367CD507), SPH_C32(0x3070DD17), + SPH_C32(0xF70E5939), SPH_C32(0xFFC00B31), SPH_C32(0x68581511), + SPH_C32(0x64F98FA7), SPH_C32(0xBEFA4FA4) +}; + +static const sph_u32 H256[8] = { + SPH_C32(0x6A09E667), SPH_C32(0xBB67AE85), SPH_C32(0x3C6EF372), + SPH_C32(0xA54FF53A), SPH_C32(0x510E527F), SPH_C32(0x9B05688C), + SPH_C32(0x1F83D9AB), SPH_C32(0x5BE0CD19) +}; + +/* + * The SHA2_ROUND_BODY defines the body for a SHA-224 / SHA-256 + * compression function implementation. The "in" parameter should + * evaluate, when applied to a numerical input parameter from 0 to 15, + * to an expression which yields the corresponding input block. The "r" + * parameter should evaluate to an array or pointer expression + * designating the array of 8 words which contains the input and output + * of the compression function. + */ + +#if SPH_SMALL_FOOTPRINT_SHA2 + +static const sph_u32 K[64] = { + SPH_C32(0x428A2F98), SPH_C32(0x71374491), + SPH_C32(0xB5C0FBCF), SPH_C32(0xE9B5DBA5), + SPH_C32(0x3956C25B), SPH_C32(0x59F111F1), + SPH_C32(0x923F82A4), SPH_C32(0xAB1C5ED5), + SPH_C32(0xD807AA98), SPH_C32(0x12835B01), + SPH_C32(0x243185BE), SPH_C32(0x550C7DC3), + SPH_C32(0x72BE5D74), SPH_C32(0x80DEB1FE), + SPH_C32(0x9BDC06A7), SPH_C32(0xC19BF174), + SPH_C32(0xE49B69C1), SPH_C32(0xEFBE4786), + SPH_C32(0x0FC19DC6), SPH_C32(0x240CA1CC), + SPH_C32(0x2DE92C6F), SPH_C32(0x4A7484AA), + SPH_C32(0x5CB0A9DC), SPH_C32(0x76F988DA), + SPH_C32(0x983E5152), SPH_C32(0xA831C66D), + SPH_C32(0xB00327C8), SPH_C32(0xBF597FC7), + SPH_C32(0xC6E00BF3), SPH_C32(0xD5A79147), + SPH_C32(0x06CA6351), SPH_C32(0x14292967), + SPH_C32(0x27B70A85), SPH_C32(0x2E1B2138), + SPH_C32(0x4D2C6DFC), SPH_C32(0x53380D13), + SPH_C32(0x650A7354), SPH_C32(0x766A0ABB), + SPH_C32(0x81C2C92E), SPH_C32(0x92722C85), + SPH_C32(0xA2BFE8A1), SPH_C32(0xA81A664B), + SPH_C32(0xC24B8B70), SPH_C32(0xC76C51A3), + SPH_C32(0xD192E819), SPH_C32(0xD6990624), + SPH_C32(0xF40E3585), SPH_C32(0x106AA070), + SPH_C32(0x19A4C116), SPH_C32(0x1E376C08), + SPH_C32(0x2748774C), SPH_C32(0x34B0BCB5), + SPH_C32(0x391C0CB3), SPH_C32(0x4ED8AA4A), + SPH_C32(0x5B9CCA4F), SPH_C32(0x682E6FF3), + SPH_C32(0x748F82EE), SPH_C32(0x78A5636F), + SPH_C32(0x84C87814), SPH_C32(0x8CC70208), + SPH_C32(0x90BEFFFA), SPH_C32(0xA4506CEB), + SPH_C32(0xBEF9A3F7), SPH_C32(0xC67178F2) +}; + +#define SHA2_MEXP1(in, pc) do { \ + W[pc] = in(pc); \ + } while (0) + +#define SHA2_MEXP2(in, pc) do { \ + W[(pc) & 0x0F] = SPH_T32(SSG2_1(W[((pc) - 2) & 0x0F]) \ + + W[((pc) - 7) & 0x0F] \ + + SSG2_0(W[((pc) - 15) & 0x0F]) + W[(pc) & 0x0F]); \ + } while (0) + +#define SHA2_STEPn(n, a, b, c, d, e, f, g, h, in, pc) do { \ + sph_u32 t1, t2; \ + SHA2_MEXP ## n(in, pc); \ + t1 = SPH_T32(h + BSG2_1(e) + CH(e, f, g) \ + + K[pcount + (pc)] + W[(pc) & 0x0F]); \ + t2 = SPH_T32(BSG2_0(a) + MAJ(a, b, c)); \ + d = SPH_T32(d + t1); \ + h = SPH_T32(t1 + t2); \ + } while (0) + +#define SHA2_STEP1(a, b, c, d, e, f, g, h, in, pc) \ + SHA2_STEPn(1, a, b, c, d, e, f, g, h, in, pc) +#define SHA2_STEP2(a, b, c, d, e, f, g, h, in, pc) \ + SHA2_STEPn(2, a, b, c, d, e, f, g, h, in, pc) + +#define SHA2_ROUND_BODY(in, r) do { \ + sph_u32 A, B, C, D, E, F, G, H; \ + sph_u32 W[16]; \ + unsigned pcount; \ + \ + A = (r)[0]; \ + B = (r)[1]; \ + C = (r)[2]; \ + D = (r)[3]; \ + E = (r)[4]; \ + F = (r)[5]; \ + G = (r)[6]; \ + H = (r)[7]; \ + pcount = 0; \ + SHA2_STEP1(A, B, C, D, E, F, G, H, in, 0); \ + SHA2_STEP1(H, A, B, C, D, E, F, G, in, 1); \ + SHA2_STEP1(G, H, A, B, C, D, E, F, in, 2); \ + SHA2_STEP1(F, G, H, A, B, C, D, E, in, 3); \ + SHA2_STEP1(E, F, G, H, A, B, C, D, in, 4); \ + SHA2_STEP1(D, E, F, G, H, A, B, C, in, 5); \ + SHA2_STEP1(C, D, E, F, G, H, A, B, in, 6); \ + SHA2_STEP1(B, C, D, E, F, G, H, A, in, 7); \ + SHA2_STEP1(A, B, C, D, E, F, G, H, in, 8); \ + SHA2_STEP1(H, A, B, C, D, E, F, G, in, 9); \ + SHA2_STEP1(G, H, A, B, C, D, E, F, in, 10); \ + SHA2_STEP1(F, G, H, A, B, C, D, E, in, 11); \ + SHA2_STEP1(E, F, G, H, A, B, C, D, in, 12); \ + SHA2_STEP1(D, E, F, G, H, A, B, C, in, 13); \ + SHA2_STEP1(C, D, E, F, G, H, A, B, in, 14); \ + SHA2_STEP1(B, C, D, E, F, G, H, A, in, 15); \ + for (pcount = 16; pcount < 64; pcount += 16) { \ + SHA2_STEP2(A, B, C, D, E, F, G, H, in, 0); \ + SHA2_STEP2(H, A, B, C, D, E, F, G, in, 1); \ + SHA2_STEP2(G, H, A, B, C, D, E, F, in, 2); \ + SHA2_STEP2(F, G, H, A, B, C, D, E, in, 3); \ + SHA2_STEP2(E, F, G, H, A, B, C, D, in, 4); \ + SHA2_STEP2(D, E, F, G, H, A, B, C, in, 5); \ + SHA2_STEP2(C, D, E, F, G, H, A, B, in, 6); \ + SHA2_STEP2(B, C, D, E, F, G, H, A, in, 7); \ + SHA2_STEP2(A, B, C, D, E, F, G, H, in, 8); \ + SHA2_STEP2(H, A, B, C, D, E, F, G, in, 9); \ + SHA2_STEP2(G, H, A, B, C, D, E, F, in, 10); \ + SHA2_STEP2(F, G, H, A, B, C, D, E, in, 11); \ + SHA2_STEP2(E, F, G, H, A, B, C, D, in, 12); \ + SHA2_STEP2(D, E, F, G, H, A, B, C, in, 13); \ + SHA2_STEP2(C, D, E, F, G, H, A, B, in, 14); \ + SHA2_STEP2(B, C, D, E, F, G, H, A, in, 15); \ + } \ + (r)[0] = SPH_T32((r)[0] + A); \ + (r)[1] = SPH_T32((r)[1] + B); \ + (r)[2] = SPH_T32((r)[2] + C); \ + (r)[3] = SPH_T32((r)[3] + D); \ + (r)[4] = SPH_T32((r)[4] + E); \ + (r)[5] = SPH_T32((r)[5] + F); \ + (r)[6] = SPH_T32((r)[6] + G); \ + (r)[7] = SPH_T32((r)[7] + H); \ + } while (0) + +#else + +#define SHA2_ROUND_BODY(in, r) do { \ + sph_u32 A, B, C, D, E, F, G, H, T1, T2; \ + sph_u32 W00, W01, W02, W03, W04, W05, W06, W07; \ + sph_u32 W08, W09, W10, W11, W12, W13, W14, W15; \ + \ + A = (r)[0]; \ + B = (r)[1]; \ + C = (r)[2]; \ + D = (r)[3]; \ + E = (r)[4]; \ + F = (r)[5]; \ + G = (r)[6]; \ + H = (r)[7]; \ + W00 = in(0); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0x428A2F98) + W00); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W01 = in(1); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0x71374491) + W01); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W02 = in(2); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0xB5C0FBCF) + W02); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W03 = in(3); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0xE9B5DBA5) + W03); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W04 = in(4); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0x3956C25B) + W04); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W05 = in(5); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0x59F111F1) + W05); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W06 = in(6); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0x923F82A4) + W06); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W07 = in(7); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0xAB1C5ED5) + W07); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W08 = in(8); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0xD807AA98) + W08); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W09 = in(9); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0x12835B01) + W09); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W10 = in(10); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0x243185BE) + W10); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W11 = in(11); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0x550C7DC3) + W11); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W12 = in(12); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0x72BE5D74) + W12); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W13 = in(13); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0x80DEB1FE) + W13); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W14 = in(14); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0x9BDC06A7) + W14); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W15 = in(15); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0xC19BF174) + W15); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W00 = SPH_T32(SSG2_1(W14) + W09 + SSG2_0(W01) + W00); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0xE49B69C1) + W00); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W01 = SPH_T32(SSG2_1(W15) + W10 + SSG2_0(W02) + W01); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0xEFBE4786) + W01); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W02 = SPH_T32(SSG2_1(W00) + W11 + SSG2_0(W03) + W02); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0x0FC19DC6) + W02); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W03 = SPH_T32(SSG2_1(W01) + W12 + SSG2_0(W04) + W03); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0x240CA1CC) + W03); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W04 = SPH_T32(SSG2_1(W02) + W13 + SSG2_0(W05) + W04); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0x2DE92C6F) + W04); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W05 = SPH_T32(SSG2_1(W03) + W14 + SSG2_0(W06) + W05); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0x4A7484AA) + W05); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W06 = SPH_T32(SSG2_1(W04) + W15 + SSG2_0(W07) + W06); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0x5CB0A9DC) + W06); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W07 = SPH_T32(SSG2_1(W05) + W00 + SSG2_0(W08) + W07); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0x76F988DA) + W07); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W08 = SPH_T32(SSG2_1(W06) + W01 + SSG2_0(W09) + W08); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0x983E5152) + W08); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W09 = SPH_T32(SSG2_1(W07) + W02 + SSG2_0(W10) + W09); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0xA831C66D) + W09); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W10 = SPH_T32(SSG2_1(W08) + W03 + SSG2_0(W11) + W10); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0xB00327C8) + W10); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W11 = SPH_T32(SSG2_1(W09) + W04 + SSG2_0(W12) + W11); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0xBF597FC7) + W11); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W12 = SPH_T32(SSG2_1(W10) + W05 + SSG2_0(W13) + W12); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0xC6E00BF3) + W12); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W13 = SPH_T32(SSG2_1(W11) + W06 + SSG2_0(W14) + W13); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0xD5A79147) + W13); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W14 = SPH_T32(SSG2_1(W12) + W07 + SSG2_0(W15) + W14); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0x06CA6351) + W14); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W15 = SPH_T32(SSG2_1(W13) + W08 + SSG2_0(W00) + W15); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0x14292967) + W15); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W00 = SPH_T32(SSG2_1(W14) + W09 + SSG2_0(W01) + W00); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0x27B70A85) + W00); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W01 = SPH_T32(SSG2_1(W15) + W10 + SSG2_0(W02) + W01); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0x2E1B2138) + W01); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W02 = SPH_T32(SSG2_1(W00) + W11 + SSG2_0(W03) + W02); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0x4D2C6DFC) + W02); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W03 = SPH_T32(SSG2_1(W01) + W12 + SSG2_0(W04) + W03); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0x53380D13) + W03); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W04 = SPH_T32(SSG2_1(W02) + W13 + SSG2_0(W05) + W04); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0x650A7354) + W04); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W05 = SPH_T32(SSG2_1(W03) + W14 + SSG2_0(W06) + W05); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0x766A0ABB) + W05); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W06 = SPH_T32(SSG2_1(W04) + W15 + SSG2_0(W07) + W06); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0x81C2C92E) + W06); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W07 = SPH_T32(SSG2_1(W05) + W00 + SSG2_0(W08) + W07); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0x92722C85) + W07); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W08 = SPH_T32(SSG2_1(W06) + W01 + SSG2_0(W09) + W08); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0xA2BFE8A1) + W08); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W09 = SPH_T32(SSG2_1(W07) + W02 + SSG2_0(W10) + W09); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0xA81A664B) + W09); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W10 = SPH_T32(SSG2_1(W08) + W03 + SSG2_0(W11) + W10); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0xC24B8B70) + W10); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W11 = SPH_T32(SSG2_1(W09) + W04 + SSG2_0(W12) + W11); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0xC76C51A3) + W11); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W12 = SPH_T32(SSG2_1(W10) + W05 + SSG2_0(W13) + W12); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0xD192E819) + W12); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W13 = SPH_T32(SSG2_1(W11) + W06 + SSG2_0(W14) + W13); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0xD6990624) + W13); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W14 = SPH_T32(SSG2_1(W12) + W07 + SSG2_0(W15) + W14); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0xF40E3585) + W14); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W15 = SPH_T32(SSG2_1(W13) + W08 + SSG2_0(W00) + W15); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0x106AA070) + W15); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W00 = SPH_T32(SSG2_1(W14) + W09 + SSG2_0(W01) + W00); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0x19A4C116) + W00); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W01 = SPH_T32(SSG2_1(W15) + W10 + SSG2_0(W02) + W01); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0x1E376C08) + W01); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W02 = SPH_T32(SSG2_1(W00) + W11 + SSG2_0(W03) + W02); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0x2748774C) + W02); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W03 = SPH_T32(SSG2_1(W01) + W12 + SSG2_0(W04) + W03); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0x34B0BCB5) + W03); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W04 = SPH_T32(SSG2_1(W02) + W13 + SSG2_0(W05) + W04); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0x391C0CB3) + W04); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W05 = SPH_T32(SSG2_1(W03) + W14 + SSG2_0(W06) + W05); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0x4ED8AA4A) + W05); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W06 = SPH_T32(SSG2_1(W04) + W15 + SSG2_0(W07) + W06); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0x5B9CCA4F) + W06); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W07 = SPH_T32(SSG2_1(W05) + W00 + SSG2_0(W08) + W07); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0x682E6FF3) + W07); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + W08 = SPH_T32(SSG2_1(W06) + W01 + SSG2_0(W09) + W08); \ + T1 = SPH_T32(H + BSG2_1(E) + CH(E, F, G) \ + + SPH_C32(0x748F82EE) + W08); \ + T2 = SPH_T32(BSG2_0(A) + MAJ(A, B, C)); \ + D = SPH_T32(D + T1); \ + H = SPH_T32(T1 + T2); \ + W09 = SPH_T32(SSG2_1(W07) + W02 + SSG2_0(W10) + W09); \ + T1 = SPH_T32(G + BSG2_1(D) + CH(D, E, F) \ + + SPH_C32(0x78A5636F) + W09); \ + T2 = SPH_T32(BSG2_0(H) + MAJ(H, A, B)); \ + C = SPH_T32(C + T1); \ + G = SPH_T32(T1 + T2); \ + W10 = SPH_T32(SSG2_1(W08) + W03 + SSG2_0(W11) + W10); \ + T1 = SPH_T32(F + BSG2_1(C) + CH(C, D, E) \ + + SPH_C32(0x84C87814) + W10); \ + T2 = SPH_T32(BSG2_0(G) + MAJ(G, H, A)); \ + B = SPH_T32(B + T1); \ + F = SPH_T32(T1 + T2); \ + W11 = SPH_T32(SSG2_1(W09) + W04 + SSG2_0(W12) + W11); \ + T1 = SPH_T32(E + BSG2_1(B) + CH(B, C, D) \ + + SPH_C32(0x8CC70208) + W11); \ + T2 = SPH_T32(BSG2_0(F) + MAJ(F, G, H)); \ + A = SPH_T32(A + T1); \ + E = SPH_T32(T1 + T2); \ + W12 = SPH_T32(SSG2_1(W10) + W05 + SSG2_0(W13) + W12); \ + T1 = SPH_T32(D + BSG2_1(A) + CH(A, B, C) \ + + SPH_C32(0x90BEFFFA) + W12); \ + T2 = SPH_T32(BSG2_0(E) + MAJ(E, F, G)); \ + H = SPH_T32(H + T1); \ + D = SPH_T32(T1 + T2); \ + W13 = SPH_T32(SSG2_1(W11) + W06 + SSG2_0(W14) + W13); \ + T1 = SPH_T32(C + BSG2_1(H) + CH(H, A, B) \ + + SPH_C32(0xA4506CEB) + W13); \ + T2 = SPH_T32(BSG2_0(D) + MAJ(D, E, F)); \ + G = SPH_T32(G + T1); \ + C = SPH_T32(T1 + T2); \ + W14 = SPH_T32(SSG2_1(W12) + W07 + SSG2_0(W15) + W14); \ + T1 = SPH_T32(B + BSG2_1(G) + CH(G, H, A) \ + + SPH_C32(0xBEF9A3F7) + W14); \ + T2 = SPH_T32(BSG2_0(C) + MAJ(C, D, E)); \ + F = SPH_T32(F + T1); \ + B = SPH_T32(T1 + T2); \ + W15 = SPH_T32(SSG2_1(W13) + W08 + SSG2_0(W00) + W15); \ + T1 = SPH_T32(A + BSG2_1(F) + CH(F, G, H) \ + + SPH_C32(0xC67178F2) + W15); \ + T2 = SPH_T32(BSG2_0(B) + MAJ(B, C, D)); \ + E = SPH_T32(E + T1); \ + A = SPH_T32(T1 + T2); \ + (r)[0] = SPH_T32((r)[0] + A); \ + (r)[1] = SPH_T32((r)[1] + B); \ + (r)[2] = SPH_T32((r)[2] + C); \ + (r)[3] = SPH_T32((r)[3] + D); \ + (r)[4] = SPH_T32((r)[4] + E); \ + (r)[5] = SPH_T32((r)[5] + F); \ + (r)[6] = SPH_T32((r)[6] + G); \ + (r)[7] = SPH_T32((r)[7] + H); \ + } while (0) + +#endif + +/* + * One round of SHA-224 / SHA-256. The data must be aligned for 32-bit access. + */ +static void +sha2_round(const unsigned char *data, sph_u32 r[8]) +{ +#define SHA2_IN(x) sph_dec32be_aligned(data + (4 * (x))) + SHA2_ROUND_BODY(SHA2_IN, r); +#undef SHA2_IN +} + +/* see sph_sha2.h */ +void +sph_sha224_init(void *cc) +{ + sph_sha224_context *sc; + + sc = cc; + memcpy(sc->val, H224, sizeof H224); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +/* see sph_sha2.h */ +void +sph_sha256_init(void *cc) +{ + sph_sha256_context *sc; + + sc = cc; + memcpy(sc->val, H256, sizeof H256); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +#define RFUN sha2_round +#define HASH sha224 +#define BE32 1 +#include "md_helper.c" + +/* see sph_sha2.h */ +void +sph_sha224_close(void *cc, void *dst) +{ + sha224_close(cc, dst, 7); + sph_sha224_init(cc); +} + +/* see sph_sha2.h */ +void +sph_sha224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + sha224_addbits_and_close(cc, ub, n, dst, 7); + sph_sha224_init(cc); +} + +/* see sph_sha2.h */ +void +sph_sha256_close(void *cc, void *dst) +{ + sha224_close(cc, dst, 8); + sph_sha256_init(cc); +} + +/* see sph_sha2.h */ +void +sph_sha256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + sha224_addbits_and_close(cc, ub, n, dst, 8); + sph_sha256_init(cc); +} + +/* see sph_sha2.h */ +void +sph_sha224_comp(const sph_u32 msg[16], sph_u32 val[8]) +{ +#define SHA2_IN(x) msg[x] + SHA2_ROUND_BODY(SHA2_IN, val); +#undef SHA2_IN +} diff --git a/sha3/sph_sha2.h b/sha3/sph_sha2.h new file mode 100644 index 000000000..d5bda731a --- /dev/null +++ b/sha3/sph_sha2.h @@ -0,0 +1,370 @@ +/* $Id: sph_sha2.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * SHA-224, SHA-256, SHA-384 and SHA-512 interface. + * + * SHA-256 has been published in FIPS 180-2, now amended with a change + * notice to include SHA-224 as well (which is a simple variation on + * SHA-256). SHA-384 and SHA-512 are also defined in FIPS 180-2. FIPS + * standards can be found at: + * http://csrc.nist.gov/publications/fips/ + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_sha2.h + * @author Thomas Pornin + */ + +#ifndef SPH_SHA2_H__ +#define SPH_SHA2_H__ + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for SHA-224. + */ +#define SPH_SIZE_sha224 224 + +/** + * Output size (in bits) for SHA-256. + */ +#define SPH_SIZE_sha256 256 + +/** + * This structure is a context for SHA-224 computations: it contains the + * intermediate values and some data from the last entered block. Once + * a SHA-224 computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running SHA-224 computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + sph_u32 val[8]; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_sha224_context; + +/** + * This structure is a context for SHA-256 computations. It is identical + * to the SHA-224 context. However, a context is initialized for SHA-224 + * or SHA-256, but not both (the internal IV is not the + * same). + */ +typedef sph_sha224_context sph_sha256_context; + +/** + * Initialize a SHA-224 context. This process performs no memory allocation. + * + * @param cc the SHA-224 context (pointer to + * a sph_sha224_context) + */ +void sph_sha224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SHA-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_sha224(void *cc, const void *data, size_t len); + +/** + * Terminate the current SHA-224 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHA-224 context + * @param dst the destination buffer + */ +void sph_sha224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHA-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_sha224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Apply the SHA-224 compression function on the provided data. The + * msg parameter contains the 16 32-bit input blocks, + * as numerical values (hence after the big-endian decoding). The + * val parameter contains the 8 32-bit input blocks for + * the compression function; the output is written in place in this + * array. + * + * @param msg the message block (16 values) + * @param val the function 256-bit input and output + */ +void sph_sha224_comp(const sph_u32 msg[16], sph_u32 val[8]); + +/** + * Initialize a SHA-256 context. This process performs no memory allocation. + * + * @param cc the SHA-256 context (pointer to + * a sph_sha256_context) + */ +void sph_sha256_init(void *cc); + +#ifdef DOXYGEN_IGNORE +/** + * Process some data bytes, for SHA-256. This function is identical to + * sha_224() + * + * @param cc the SHA-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_sha256(void *cc, const void *data, size_t len); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_sha256 sph_sha224 +#endif + +/** + * Terminate the current SHA-256 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHA-256 context + * @param dst the destination buffer + */ +void sph_sha256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHA-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_sha256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef DOXYGEN_IGNORE +/** + * Apply the SHA-256 compression function on the provided data. This + * function is identical to sha224_comp(). + * + * @param msg the message block (16 values) + * @param val the function 256-bit input and output + */ +void sph_sha256_comp(const sph_u32 msg[16], sph_u32 val[8]); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_sha256_comp sph_sha224_comp +#endif + +#if SPH_64 + +/** + * Output size (in bits) for SHA-384. + */ +#define SPH_SIZE_sha384 384 + +/** + * Output size (in bits) for SHA-512. + */ +#define SPH_SIZE_sha512 512 + +/** + * This structure is a context for SHA-384 computations: it contains the + * intermediate values and some data from the last entered block. Once + * a SHA-384 computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running SHA-384 computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + sph_u64 val[8]; + sph_u64 count; +#endif +} sph_sha384_context; + +/** + * Initialize a SHA-384 context. This process performs no memory allocation. + * + * @param cc the SHA-384 context (pointer to + * a sph_sha384_context) + */ +void sph_sha384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SHA-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_sha384(void *cc, const void *data, size_t len); + +/** + * Terminate the current SHA-384 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHA-384 context + * @param dst the destination buffer + */ +void sph_sha384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHA-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_sha384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Apply the SHA-384 compression function on the provided data. The + * msg parameter contains the 16 64-bit input blocks, + * as numerical values (hence after the big-endian decoding). The + * val parameter contains the 8 64-bit input blocks for + * the compression function; the output is written in place in this + * array. + * + * @param msg the message block (16 values) + * @param val the function 512-bit input and output + */ +void sph_sha384_comp(const sph_u64 msg[16], sph_u64 val[8]); + +/** + * This structure is a context for SHA-512 computations. It is identical + * to the SHA-384 context. However, a context is initialized for SHA-384 + * or SHA-512, but not both (the internal IV is not the + * same). + */ +typedef sph_sha384_context sph_sha512_context; + +/** + * Initialize a SHA-512 context. This process performs no memory allocation. + * + * @param cc the SHA-512 context (pointer to + * a sph_sha512_context) + */ +void sph_sha512_init(void *cc); + +#ifdef DOXYGEN_IGNORE +/** + * Process some data bytes, for SHA-512. This function is identical to + * sph_sha384(). + * + * @param cc the SHA-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_sha512(void *cc, const void *data, size_t len); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_sha512 sph_sha384 +#endif + +/** + * Terminate the current SHA-512 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHA-512 context + * @param dst the destination buffer + */ +void sph_sha512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHA-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_sha512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef DOXYGEN_IGNORE +/** + * Apply the SHA-512 compression function. This function is identical to + * sph_sha384_comp(). + * + * @param msg the message block (16 values) + * @param val the function 512-bit input and output + */ +void sph_sha512_comp(const sph_u64 msg[16], sph_u64 val[8]); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_sha512_comp sph_sha384_comp +#endif + +#endif + +#endif diff --git a/sha3/sph_sha2big.c b/sha3/sph_sha2big.c new file mode 100644 index 000000000..cc7de878f --- /dev/null +++ b/sha3/sph_sha2big.c @@ -0,0 +1,247 @@ +/* $Id: sha2big.c 216 2010-06-08 09:46:57Z tp $ */ +/* + * SHA-384 / SHA-512 implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_sha2.h" + +#if SPH_64 + +#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z)) +#define MAJ(X, Y, Z) (((X) & (Y)) | (((X) | (Y)) & (Z))) + +#define ROTR64 SPH_ROTR64 + +#define BSG5_0(x) (ROTR64(x, 28) ^ ROTR64(x, 34) ^ ROTR64(x, 39)) +#define BSG5_1(x) (ROTR64(x, 14) ^ ROTR64(x, 18) ^ ROTR64(x, 41)) +#define SSG5_0(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ SPH_T64((x) >> 7)) +#define SSG5_1(x) (ROTR64(x, 19) ^ ROTR64(x, 61) ^ SPH_T64((x) >> 6)) + +static const sph_u64 K512[80] = { + SPH_C64(0x428A2F98D728AE22), SPH_C64(0x7137449123EF65CD), + SPH_C64(0xB5C0FBCFEC4D3B2F), SPH_C64(0xE9B5DBA58189DBBC), + SPH_C64(0x3956C25BF348B538), SPH_C64(0x59F111F1B605D019), + SPH_C64(0x923F82A4AF194F9B), SPH_C64(0xAB1C5ED5DA6D8118), + SPH_C64(0xD807AA98A3030242), SPH_C64(0x12835B0145706FBE), + SPH_C64(0x243185BE4EE4B28C), SPH_C64(0x550C7DC3D5FFB4E2), + SPH_C64(0x72BE5D74F27B896F), SPH_C64(0x80DEB1FE3B1696B1), + SPH_C64(0x9BDC06A725C71235), SPH_C64(0xC19BF174CF692694), + SPH_C64(0xE49B69C19EF14AD2), SPH_C64(0xEFBE4786384F25E3), + SPH_C64(0x0FC19DC68B8CD5B5), SPH_C64(0x240CA1CC77AC9C65), + SPH_C64(0x2DE92C6F592B0275), SPH_C64(0x4A7484AA6EA6E483), + SPH_C64(0x5CB0A9DCBD41FBD4), SPH_C64(0x76F988DA831153B5), + SPH_C64(0x983E5152EE66DFAB), SPH_C64(0xA831C66D2DB43210), + SPH_C64(0xB00327C898FB213F), SPH_C64(0xBF597FC7BEEF0EE4), + SPH_C64(0xC6E00BF33DA88FC2), SPH_C64(0xD5A79147930AA725), + SPH_C64(0x06CA6351E003826F), SPH_C64(0x142929670A0E6E70), + SPH_C64(0x27B70A8546D22FFC), SPH_C64(0x2E1B21385C26C926), + SPH_C64(0x4D2C6DFC5AC42AED), SPH_C64(0x53380D139D95B3DF), + SPH_C64(0x650A73548BAF63DE), SPH_C64(0x766A0ABB3C77B2A8), + SPH_C64(0x81C2C92E47EDAEE6), SPH_C64(0x92722C851482353B), + SPH_C64(0xA2BFE8A14CF10364), SPH_C64(0xA81A664BBC423001), + SPH_C64(0xC24B8B70D0F89791), SPH_C64(0xC76C51A30654BE30), + SPH_C64(0xD192E819D6EF5218), SPH_C64(0xD69906245565A910), + SPH_C64(0xF40E35855771202A), SPH_C64(0x106AA07032BBD1B8), + SPH_C64(0x19A4C116B8D2D0C8), SPH_C64(0x1E376C085141AB53), + SPH_C64(0x2748774CDF8EEB99), SPH_C64(0x34B0BCB5E19B48A8), + SPH_C64(0x391C0CB3C5C95A63), SPH_C64(0x4ED8AA4AE3418ACB), + SPH_C64(0x5B9CCA4F7763E373), SPH_C64(0x682E6FF3D6B2B8A3), + SPH_C64(0x748F82EE5DEFB2FC), SPH_C64(0x78A5636F43172F60), + SPH_C64(0x84C87814A1F0AB72), SPH_C64(0x8CC702081A6439EC), + SPH_C64(0x90BEFFFA23631E28), SPH_C64(0xA4506CEBDE82BDE9), + SPH_C64(0xBEF9A3F7B2C67915), SPH_C64(0xC67178F2E372532B), + SPH_C64(0xCA273ECEEA26619C), SPH_C64(0xD186B8C721C0C207), + SPH_C64(0xEADA7DD6CDE0EB1E), SPH_C64(0xF57D4F7FEE6ED178), + SPH_C64(0x06F067AA72176FBA), SPH_C64(0x0A637DC5A2C898A6), + SPH_C64(0x113F9804BEF90DAE), SPH_C64(0x1B710B35131C471B), + SPH_C64(0x28DB77F523047D84), SPH_C64(0x32CAAB7B40C72493), + SPH_C64(0x3C9EBE0A15C9BEBC), SPH_C64(0x431D67C49C100D4C), + SPH_C64(0x4CC5D4BECB3E42B6), SPH_C64(0x597F299CFC657E2A), + SPH_C64(0x5FCB6FAB3AD6FAEC), SPH_C64(0x6C44198C4A475817) +}; + +static const sph_u64 H384[8] = { + SPH_C64(0xCBBB9D5DC1059ED8), SPH_C64(0x629A292A367CD507), + SPH_C64(0x9159015A3070DD17), SPH_C64(0x152FECD8F70E5939), + SPH_C64(0x67332667FFC00B31), SPH_C64(0x8EB44A8768581511), + SPH_C64(0xDB0C2E0D64F98FA7), SPH_C64(0x47B5481DBEFA4FA4) +}; + +static const sph_u64 H512[8] = { + SPH_C64(0x6A09E667F3BCC908), SPH_C64(0xBB67AE8584CAA73B), + SPH_C64(0x3C6EF372FE94F82B), SPH_C64(0xA54FF53A5F1D36F1), + SPH_C64(0x510E527FADE682D1), SPH_C64(0x9B05688C2B3E6C1F), + SPH_C64(0x1F83D9ABFB41BD6B), SPH_C64(0x5BE0CD19137E2179) +}; + +/* + * This macro defines the body for a SHA-384 / SHA-512 compression function + * implementation. The "in" parameter should evaluate, when applied to a + * numerical input parameter from 0 to 15, to an expression which yields + * the corresponding input block. The "r" parameter should evaluate to + * an array or pointer expression designating the array of 8 words which + * contains the input and output of the compression function. + * + * SHA-512 is hard for the compiler. If the loop is completely unrolled, + * then the code will be quite huge (possibly more than 100 kB), and the + * performance will be degraded due to cache misses on the code. We + * unroll only eight steps, which avoids all needless copies when + * 64-bit registers are swapped. + */ + +#define SHA3_STEP(A, B, C, D, E, F, G, H, i) do { \ + sph_u64 T1, T2; \ + T1 = SPH_T64(H + BSG5_1(E) + CH(E, F, G) + K512[i] + W[i]); \ + T2 = SPH_T64(BSG5_0(A) + MAJ(A, B, C)); \ + D = SPH_T64(D + T1); \ + H = SPH_T64(T1 + T2); \ + } while (0) + +#define SHA3_ROUND_BODY(in, r) do { \ + int i; \ + sph_u64 A, B, C, D, E, F, G, H; \ + sph_u64 W[80]; \ + \ + for (i = 0; i < 16; i ++) \ + W[i] = in(i); \ + for (i = 16; i < 80; i ++) \ + W[i] = SPH_T64(SSG5_1(W[i - 2]) + W[i - 7] \ + + SSG5_0(W[i - 15]) + W[i - 16]); \ + A = (r)[0]; \ + B = (r)[1]; \ + C = (r)[2]; \ + D = (r)[3]; \ + E = (r)[4]; \ + F = (r)[5]; \ + G = (r)[6]; \ + H = (r)[7]; \ + for (i = 0; i < 80; i += 8) { \ + SHA3_STEP(A, B, C, D, E, F, G, H, i + 0); \ + SHA3_STEP(H, A, B, C, D, E, F, G, i + 1); \ + SHA3_STEP(G, H, A, B, C, D, E, F, i + 2); \ + SHA3_STEP(F, G, H, A, B, C, D, E, i + 3); \ + SHA3_STEP(E, F, G, H, A, B, C, D, i + 4); \ + SHA3_STEP(D, E, F, G, H, A, B, C, i + 5); \ + SHA3_STEP(C, D, E, F, G, H, A, B, i + 6); \ + SHA3_STEP(B, C, D, E, F, G, H, A, i + 7); \ + } \ + (r)[0] = SPH_T64((r)[0] + A); \ + (r)[1] = SPH_T64((r)[1] + B); \ + (r)[2] = SPH_T64((r)[2] + C); \ + (r)[3] = SPH_T64((r)[3] + D); \ + (r)[4] = SPH_T64((r)[4] + E); \ + (r)[5] = SPH_T64((r)[5] + F); \ + (r)[6] = SPH_T64((r)[6] + G); \ + (r)[7] = SPH_T64((r)[7] + H); \ + } while (0) + +/* + * One round of SHA-384 / SHA-512. The data must be aligned for 64-bit access. + */ +static void +sha3_round(const unsigned char *data, sph_u64 r[8]) +{ +#define SHA3_IN(x) sph_dec64be_aligned(data + (8 * (x))) + SHA3_ROUND_BODY(SHA3_IN, r); +#undef SHA3_IN +} + +/* see sph_sha3.h */ +void +sph_sha384_init(void *cc) +{ + sph_sha384_context *sc; + + sc = cc; + memcpy(sc->val, H384, sizeof H384); + sc->count = 0; +} + +/* see sph_sha3.h */ +void +sph_sha512_init(void *cc) +{ + sph_sha512_context *sc; + + sc = cc; + memcpy(sc->val, H512, sizeof H512); + sc->count = 0; +} + +#define RFUN sha3_round +#define HASH sha384 +#define BE64 1 +#include "md_helper.c" + +/* see sph_sha3.h */ +void +sph_sha384_close(void *cc, void *dst) +{ + sha384_close(cc, dst, 6); + sph_sha384_init(cc); +} + +/* see sph_sha3.h */ +void +sph_sha384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + sha384_addbits_and_close(cc, ub, n, dst, 6); + sph_sha384_init(cc); +} + +/* see sph_sha3.h */ +void +sph_sha512_close(void *cc, void *dst) +{ + sha384_close(cc, dst, 8); + sph_sha512_init(cc); +} + +/* see sph_sha3.h */ +void +sph_sha512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + sha384_addbits_and_close(cc, ub, n, dst, 8); + sph_sha512_init(cc); +} + +/* see sph_sha3.h */ +void +sph_sha384_comp(const sph_u64 msg[16], sph_u64 val[8]) +{ +#define SHA3_IN(x) msg[x] + SHA3_ROUND_BODY(SHA3_IN, val); +#undef SHA3_IN +} + +#endif diff --git a/sha3/sph_shabal.c b/sha3/sph_shabal.c index 23d20602f..46fe962ea 100644 --- a/sha3/sph_shabal.c +++ b/sha3/sph_shabal.c @@ -660,7 +660,7 @@ shabal_close(void *cc, unsigned ub, unsigned n, void *dst, unsigned size_words) memcpy(dst, u.tmp_out + (sizeof u.tmp_out) - out_len, out_len); shabal_init(sc, size_words << 5); } - +#if 0 /* see sph_shabal.h */ void sph_shabal192_init(void *cc) @@ -717,6 +717,7 @@ sph_shabal224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) shabal_close(cc, ub, n, dst, 7); } +#endif /* see sph_shabal.h */ void sph_shabal256_init(void *cc) @@ -745,6 +746,7 @@ sph_shabal256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) shabal_close(cc, ub, n, dst, 8); } +#if 0 /* see sph_shabal.h */ void sph_shabal384_init(void *cc) @@ -772,6 +774,7 @@ sph_shabal384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) { shabal_close(cc, ub, n, dst, 12); } +#endif /* see sph_shabal.h */ void diff --git a/sha3/sph_shavite.c b/sha3/sph_shavite.c index 85074f334..ad307f95d 100644 --- a/sha3/sph_shavite.c +++ b/sha3/sph_shavite.c @@ -1523,7 +1523,7 @@ shavite_small_close(sph_shavite_small_context *sc, buf = sc->buf; ptr = sc->ptr; - count0 = (sc->count0 += (ptr << 3) + n); + count0 = (sc->count0 += SPH_T32(ptr << 3) + n); count1 = sc->count1; z = 0x80 >> n; z = ((ub & -z) | z) & 0xFF; @@ -1543,8 +1543,8 @@ shavite_small_close(sph_shavite_small_context *sc, } sph_enc32le(buf + 54, count0); sph_enc32le(buf + 58, count1); - buf[62] = out_size_w32 << 5; - buf[63] = out_size_w32 >> 3; + buf[62] = (unsigned char) (out_size_w32 << 5); + buf[63] = (unsigned char) (out_size_w32 >> 3); c256(sc, buf); for (u = 0; u < out_size_w32; u ++) sph_enc32le((unsigned char *)dst + (u << 2), sc->h[u]); @@ -1608,7 +1608,7 @@ shavite_big_close(sph_shavite_big_context *sc, buf = sc->buf; ptr = sc->ptr; - count0 = (sc->count0 += (ptr << 3) + n); + count0 = (sc->count0 += SPH_T32(ptr << 3) + n); count1 = sc->count1; count2 = sc->count2; count3 = sc->count3; @@ -1632,8 +1632,8 @@ shavite_big_close(sph_shavite_big_context *sc, sph_enc32le(buf + 114, count1); sph_enc32le(buf + 118, count2); sph_enc32le(buf + 122, count3); - buf[126] = out_size_w32 << 5; - buf[127] = out_size_w32 >> 3; + buf[126] = (unsigned char) (out_size_w32 << 5); + buf[127] = (unsigned char) (out_size_w32 >> 3); c512(sc, buf); for (u = 0; u < out_size_w32; u ++) sph_enc32le((unsigned char *)dst + (u << 2), sc->h[u]); diff --git a/sha3/sph_simd.c b/sha3/sph_simd.c index 2c8062617..222b26bf5 100644 --- a/sha3/sph_simd.c +++ b/sha3/sph_simd.c @@ -1635,7 +1635,7 @@ encode_count_small(unsigned char *dst, { low = T32(low << 9); high = T32(high << 9) + (low >> 23); - low += (ptr << 3) + n; + low += T32(ptr << 3) + n; sph_enc32le(dst, low); sph_enc32le(dst + 4, high); } @@ -1646,7 +1646,7 @@ encode_count_big(unsigned char *dst, { low = T32(low << 10); high = T32(high << 10) + (low >> 22); - low += (ptr << 3) + n; + low += T32(ptr << 3) + n; sph_enc32le(dst, low); sph_enc32le(dst + 4, high); } diff --git a/sha3/sph_tiger.c b/sha3/sph_tiger.c new file mode 100644 index 000000000..255baa0c4 --- /dev/null +++ b/sha3/sph_tiger.c @@ -0,0 +1,697 @@ +/* $Id: tiger.c 216 2010-06-08 09:46:57Z tp $ */ +/* + * Tiger / Tiger2 implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_tiger.h" + +#if SPH_64 + +static const sph_u64 T1[256] = { + SPH_C64(0x02AAB17CF7E90C5E), SPH_C64(0xAC424B03E243A8EC), + SPH_C64(0x72CD5BE30DD5FCD3), SPH_C64(0x6D019B93F6F97F3A), + SPH_C64(0xCD9978FFD21F9193), SPH_C64(0x7573A1C9708029E2), + SPH_C64(0xB164326B922A83C3), SPH_C64(0x46883EEE04915870), + SPH_C64(0xEAACE3057103ECE6), SPH_C64(0xC54169B808A3535C), + SPH_C64(0x4CE754918DDEC47C), SPH_C64(0x0AA2F4DFDC0DF40C), + SPH_C64(0x10B76F18A74DBEFA), SPH_C64(0xC6CCB6235AD1AB6A), + SPH_C64(0x13726121572FE2FF), SPH_C64(0x1A488C6F199D921E), + SPH_C64(0x4BC9F9F4DA0007CA), SPH_C64(0x26F5E6F6E85241C7), + SPH_C64(0x859079DBEA5947B6), SPH_C64(0x4F1885C5C99E8C92), + SPH_C64(0xD78E761EA96F864B), SPH_C64(0x8E36428C52B5C17D), + SPH_C64(0x69CF6827373063C1), SPH_C64(0xB607C93D9BB4C56E), + SPH_C64(0x7D820E760E76B5EA), SPH_C64(0x645C9CC6F07FDC42), + SPH_C64(0xBF38A078243342E0), SPH_C64(0x5F6B343C9D2E7D04), + SPH_C64(0xF2C28AEB600B0EC6), SPH_C64(0x6C0ED85F7254BCAC), + SPH_C64(0x71592281A4DB4FE5), SPH_C64(0x1967FA69CE0FED9F), + SPH_C64(0xFD5293F8B96545DB), SPH_C64(0xC879E9D7F2A7600B), + SPH_C64(0x860248920193194E), SPH_C64(0xA4F9533B2D9CC0B3), + SPH_C64(0x9053836C15957613), SPH_C64(0xDB6DCF8AFC357BF1), + SPH_C64(0x18BEEA7A7A370F57), SPH_C64(0x037117CA50B99066), + SPH_C64(0x6AB30A9774424A35), SPH_C64(0xF4E92F02E325249B), + SPH_C64(0x7739DB07061CCAE1), SPH_C64(0xD8F3B49CECA42A05), + SPH_C64(0xBD56BE3F51382F73), SPH_C64(0x45FAED5843B0BB28), + SPH_C64(0x1C813D5C11BF1F83), SPH_C64(0x8AF0E4B6D75FA169), + SPH_C64(0x33EE18A487AD9999), SPH_C64(0x3C26E8EAB1C94410), + SPH_C64(0xB510102BC0A822F9), SPH_C64(0x141EEF310CE6123B), + SPH_C64(0xFC65B90059DDB154), SPH_C64(0xE0158640C5E0E607), + SPH_C64(0x884E079826C3A3CF), SPH_C64(0x930D0D9523C535FD), + SPH_C64(0x35638D754E9A2B00), SPH_C64(0x4085FCCF40469DD5), + SPH_C64(0xC4B17AD28BE23A4C), SPH_C64(0xCAB2F0FC6A3E6A2E), + SPH_C64(0x2860971A6B943FCD), SPH_C64(0x3DDE6EE212E30446), + SPH_C64(0x6222F32AE01765AE), SPH_C64(0x5D550BB5478308FE), + SPH_C64(0xA9EFA98DA0EDA22A), SPH_C64(0xC351A71686C40DA7), + SPH_C64(0x1105586D9C867C84), SPH_C64(0xDCFFEE85FDA22853), + SPH_C64(0xCCFBD0262C5EEF76), SPH_C64(0xBAF294CB8990D201), + SPH_C64(0xE69464F52AFAD975), SPH_C64(0x94B013AFDF133E14), + SPH_C64(0x06A7D1A32823C958), SPH_C64(0x6F95FE5130F61119), + SPH_C64(0xD92AB34E462C06C0), SPH_C64(0xED7BDE33887C71D2), + SPH_C64(0x79746D6E6518393E), SPH_C64(0x5BA419385D713329), + SPH_C64(0x7C1BA6B948A97564), SPH_C64(0x31987C197BFDAC67), + SPH_C64(0xDE6C23C44B053D02), SPH_C64(0x581C49FED002D64D), + SPH_C64(0xDD474D6338261571), SPH_C64(0xAA4546C3E473D062), + SPH_C64(0x928FCE349455F860), SPH_C64(0x48161BBACAAB94D9), + SPH_C64(0x63912430770E6F68), SPH_C64(0x6EC8A5E602C6641C), + SPH_C64(0x87282515337DDD2B), SPH_C64(0x2CDA6B42034B701B), + SPH_C64(0xB03D37C181CB096D), SPH_C64(0xE108438266C71C6F), + SPH_C64(0x2B3180C7EB51B255), SPH_C64(0xDF92B82F96C08BBC), + SPH_C64(0x5C68C8C0A632F3BA), SPH_C64(0x5504CC861C3D0556), + SPH_C64(0xABBFA4E55FB26B8F), SPH_C64(0x41848B0AB3BACEB4), + SPH_C64(0xB334A273AA445D32), SPH_C64(0xBCA696F0A85AD881), + SPH_C64(0x24F6EC65B528D56C), SPH_C64(0x0CE1512E90F4524A), + SPH_C64(0x4E9DD79D5506D35A), SPH_C64(0x258905FAC6CE9779), + SPH_C64(0x2019295B3E109B33), SPH_C64(0xF8A9478B73A054CC), + SPH_C64(0x2924F2F934417EB0), SPH_C64(0x3993357D536D1BC4), + SPH_C64(0x38A81AC21DB6FF8B), SPH_C64(0x47C4FBF17D6016BF), + SPH_C64(0x1E0FAADD7667E3F5), SPH_C64(0x7ABCFF62938BEB96), + SPH_C64(0xA78DAD948FC179C9), SPH_C64(0x8F1F98B72911E50D), + SPH_C64(0x61E48EAE27121A91), SPH_C64(0x4D62F7AD31859808), + SPH_C64(0xECEBA345EF5CEAEB), SPH_C64(0xF5CEB25EBC9684CE), + SPH_C64(0xF633E20CB7F76221), SPH_C64(0xA32CDF06AB8293E4), + SPH_C64(0x985A202CA5EE2CA4), SPH_C64(0xCF0B8447CC8A8FB1), + SPH_C64(0x9F765244979859A3), SPH_C64(0xA8D516B1A1240017), + SPH_C64(0x0BD7BA3EBB5DC726), SPH_C64(0xE54BCA55B86ADB39), + SPH_C64(0x1D7A3AFD6C478063), SPH_C64(0x519EC608E7669EDD), + SPH_C64(0x0E5715A2D149AA23), SPH_C64(0x177D4571848FF194), + SPH_C64(0xEEB55F3241014C22), SPH_C64(0x0F5E5CA13A6E2EC2), + SPH_C64(0x8029927B75F5C361), SPH_C64(0xAD139FABC3D6E436), + SPH_C64(0x0D5DF1A94CCF402F), SPH_C64(0x3E8BD948BEA5DFC8), + SPH_C64(0xA5A0D357BD3FF77E), SPH_C64(0xA2D12E251F74F645), + SPH_C64(0x66FD9E525E81A082), SPH_C64(0x2E0C90CE7F687A49), + SPH_C64(0xC2E8BCBEBA973BC5), SPH_C64(0x000001BCE509745F), + SPH_C64(0x423777BBE6DAB3D6), SPH_C64(0xD1661C7EAEF06EB5), + SPH_C64(0xA1781F354DAACFD8), SPH_C64(0x2D11284A2B16AFFC), + SPH_C64(0xF1FC4F67FA891D1F), SPH_C64(0x73ECC25DCB920ADA), + SPH_C64(0xAE610C22C2A12651), SPH_C64(0x96E0A810D356B78A), + SPH_C64(0x5A9A381F2FE7870F), SPH_C64(0xD5AD62EDE94E5530), + SPH_C64(0xD225E5E8368D1427), SPH_C64(0x65977B70C7AF4631), + SPH_C64(0x99F889B2DE39D74F), SPH_C64(0x233F30BF54E1D143), + SPH_C64(0x9A9675D3D9A63C97), SPH_C64(0x5470554FF334F9A8), + SPH_C64(0x166ACB744A4F5688), SPH_C64(0x70C74CAAB2E4AEAD), + SPH_C64(0xF0D091646F294D12), SPH_C64(0x57B82A89684031D1), + SPH_C64(0xEFD95A5A61BE0B6B), SPH_C64(0x2FBD12E969F2F29A), + SPH_C64(0x9BD37013FEFF9FE8), SPH_C64(0x3F9B0404D6085A06), + SPH_C64(0x4940C1F3166CFE15), SPH_C64(0x09542C4DCDF3DEFB), + SPH_C64(0xB4C5218385CD5CE3), SPH_C64(0xC935B7DC4462A641), + SPH_C64(0x3417F8A68ED3B63F), SPH_C64(0xB80959295B215B40), + SPH_C64(0xF99CDAEF3B8C8572), SPH_C64(0x018C0614F8FCB95D), + SPH_C64(0x1B14ACCD1A3ACDF3), SPH_C64(0x84D471F200BB732D), + SPH_C64(0xC1A3110E95E8DA16), SPH_C64(0x430A7220BF1A82B8), + SPH_C64(0xB77E090D39DF210E), SPH_C64(0x5EF4BD9F3CD05E9D), + SPH_C64(0x9D4FF6DA7E57A444), SPH_C64(0xDA1D60E183D4A5F8), + SPH_C64(0xB287C38417998E47), SPH_C64(0xFE3EDC121BB31886), + SPH_C64(0xC7FE3CCC980CCBEF), SPH_C64(0xE46FB590189BFD03), + SPH_C64(0x3732FD469A4C57DC), SPH_C64(0x7EF700A07CF1AD65), + SPH_C64(0x59C64468A31D8859), SPH_C64(0x762FB0B4D45B61F6), + SPH_C64(0x155BAED099047718), SPH_C64(0x68755E4C3D50BAA6), + SPH_C64(0xE9214E7F22D8B4DF), SPH_C64(0x2ADDBF532EAC95F4), + SPH_C64(0x32AE3909B4BD0109), SPH_C64(0x834DF537B08E3450), + SPH_C64(0xFA209DA84220728D), SPH_C64(0x9E691D9B9EFE23F7), + SPH_C64(0x0446D288C4AE8D7F), SPH_C64(0x7B4CC524E169785B), + SPH_C64(0x21D87F0135CA1385), SPH_C64(0xCEBB400F137B8AA5), + SPH_C64(0x272E2B66580796BE), SPH_C64(0x3612264125C2B0DE), + SPH_C64(0x057702BDAD1EFBB2), SPH_C64(0xD4BABB8EACF84BE9), + SPH_C64(0x91583139641BC67B), SPH_C64(0x8BDC2DE08036E024), + SPH_C64(0x603C8156F49F68ED), SPH_C64(0xF7D236F7DBEF5111), + SPH_C64(0x9727C4598AD21E80), SPH_C64(0xA08A0896670A5FD7), + SPH_C64(0xCB4A8F4309EBA9CB), SPH_C64(0x81AF564B0F7036A1), + SPH_C64(0xC0B99AA778199ABD), SPH_C64(0x959F1EC83FC8E952), + SPH_C64(0x8C505077794A81B9), SPH_C64(0x3ACAAF8F056338F0), + SPH_C64(0x07B43F50627A6778), SPH_C64(0x4A44AB49F5ECCC77), + SPH_C64(0x3BC3D6E4B679EE98), SPH_C64(0x9CC0D4D1CF14108C), + SPH_C64(0x4406C00B206BC8A0), SPH_C64(0x82A18854C8D72D89), + SPH_C64(0x67E366B35C3C432C), SPH_C64(0xB923DD61102B37F2), + SPH_C64(0x56AB2779D884271D), SPH_C64(0xBE83E1B0FF1525AF), + SPH_C64(0xFB7C65D4217E49A9), SPH_C64(0x6BDBE0E76D48E7D4), + SPH_C64(0x08DF828745D9179E), SPH_C64(0x22EA6A9ADD53BD34), + SPH_C64(0xE36E141C5622200A), SPH_C64(0x7F805D1B8CB750EE), + SPH_C64(0xAFE5C7A59F58E837), SPH_C64(0xE27F996A4FB1C23C), + SPH_C64(0xD3867DFB0775F0D0), SPH_C64(0xD0E673DE6E88891A), + SPH_C64(0x123AEB9EAFB86C25), SPH_C64(0x30F1D5D5C145B895), + SPH_C64(0xBB434A2DEE7269E7), SPH_C64(0x78CB67ECF931FA38), + SPH_C64(0xF33B0372323BBF9C), SPH_C64(0x52D66336FB279C74), + SPH_C64(0x505F33AC0AFB4EAA), SPH_C64(0xE8A5CD99A2CCE187), + SPH_C64(0x534974801E2D30BB), SPH_C64(0x8D2D5711D5876D90), + SPH_C64(0x1F1A412891BC038E), SPH_C64(0xD6E2E71D82E56648), + SPH_C64(0x74036C3A497732B7), SPH_C64(0x89B67ED96361F5AB), + SPH_C64(0xFFED95D8F1EA02A2), SPH_C64(0xE72B3BD61464D43D), + SPH_C64(0xA6300F170BDC4820), SPH_C64(0xEBC18760ED78A77A), +}; + +static const sph_u64 T2[256] = { + SPH_C64(0xE6A6BE5A05A12138), SPH_C64(0xB5A122A5B4F87C98), + SPH_C64(0x563C6089140B6990), SPH_C64(0x4C46CB2E391F5DD5), + SPH_C64(0xD932ADDBC9B79434), SPH_C64(0x08EA70E42015AFF5), + SPH_C64(0xD765A6673E478CF1), SPH_C64(0xC4FB757EAB278D99), + SPH_C64(0xDF11C6862D6E0692), SPH_C64(0xDDEB84F10D7F3B16), + SPH_C64(0x6F2EF604A665EA04), SPH_C64(0x4A8E0F0FF0E0DFB3), + SPH_C64(0xA5EDEEF83DBCBA51), SPH_C64(0xFC4F0A2A0EA4371E), + SPH_C64(0xE83E1DA85CB38429), SPH_C64(0xDC8FF882BA1B1CE2), + SPH_C64(0xCD45505E8353E80D), SPH_C64(0x18D19A00D4DB0717), + SPH_C64(0x34A0CFEDA5F38101), SPH_C64(0x0BE77E518887CAF2), + SPH_C64(0x1E341438B3C45136), SPH_C64(0xE05797F49089CCF9), + SPH_C64(0xFFD23F9DF2591D14), SPH_C64(0x543DDA228595C5CD), + SPH_C64(0x661F81FD99052A33), SPH_C64(0x8736E641DB0F7B76), + SPH_C64(0x15227725418E5307), SPH_C64(0xE25F7F46162EB2FA), + SPH_C64(0x48A8B2126C13D9FE), SPH_C64(0xAFDC541792E76EEA), + SPH_C64(0x03D912BFC6D1898F), SPH_C64(0x31B1AAFA1B83F51B), + SPH_C64(0xF1AC2796E42AB7D9), SPH_C64(0x40A3A7D7FCD2EBAC), + SPH_C64(0x1056136D0AFBBCC5), SPH_C64(0x7889E1DD9A6D0C85), + SPH_C64(0xD33525782A7974AA), SPH_C64(0xA7E25D09078AC09B), + SPH_C64(0xBD4138B3EAC6EDD0), SPH_C64(0x920ABFBE71EB9E70), + SPH_C64(0xA2A5D0F54FC2625C), SPH_C64(0xC054E36B0B1290A3), + SPH_C64(0xF6DD59FF62FE932B), SPH_C64(0x3537354511A8AC7D), + SPH_C64(0xCA845E9172FADCD4), SPH_C64(0x84F82B60329D20DC), + SPH_C64(0x79C62CE1CD672F18), SPH_C64(0x8B09A2ADD124642C), + SPH_C64(0xD0C1E96A19D9E726), SPH_C64(0x5A786A9B4BA9500C), + SPH_C64(0x0E020336634C43F3), SPH_C64(0xC17B474AEB66D822), + SPH_C64(0x6A731AE3EC9BAAC2), SPH_C64(0x8226667AE0840258), + SPH_C64(0x67D4567691CAECA5), SPH_C64(0x1D94155C4875ADB5), + SPH_C64(0x6D00FD985B813FDF), SPH_C64(0x51286EFCB774CD06), + SPH_C64(0x5E8834471FA744AF), SPH_C64(0xF72CA0AEE761AE2E), + SPH_C64(0xBE40E4CDAEE8E09A), SPH_C64(0xE9970BBB5118F665), + SPH_C64(0x726E4BEB33DF1964), SPH_C64(0x703B000729199762), + SPH_C64(0x4631D816F5EF30A7), SPH_C64(0xB880B5B51504A6BE), + SPH_C64(0x641793C37ED84B6C), SPH_C64(0x7B21ED77F6E97D96), + SPH_C64(0x776306312EF96B73), SPH_C64(0xAE528948E86FF3F4), + SPH_C64(0x53DBD7F286A3F8F8), SPH_C64(0x16CADCE74CFC1063), + SPH_C64(0x005C19BDFA52C6DD), SPH_C64(0x68868F5D64D46AD3), + SPH_C64(0x3A9D512CCF1E186A), SPH_C64(0x367E62C2385660AE), + SPH_C64(0xE359E7EA77DCB1D7), SPH_C64(0x526C0773749ABE6E), + SPH_C64(0x735AE5F9D09F734B), SPH_C64(0x493FC7CC8A558BA8), + SPH_C64(0xB0B9C1533041AB45), SPH_C64(0x321958BA470A59BD), + SPH_C64(0x852DB00B5F46C393), SPH_C64(0x91209B2BD336B0E5), + SPH_C64(0x6E604F7D659EF19F), SPH_C64(0xB99A8AE2782CCB24), + SPH_C64(0xCCF52AB6C814C4C7), SPH_C64(0x4727D9AFBE11727B), + SPH_C64(0x7E950D0C0121B34D), SPH_C64(0x756F435670AD471F), + SPH_C64(0xF5ADD442615A6849), SPH_C64(0x4E87E09980B9957A), + SPH_C64(0x2ACFA1DF50AEE355), SPH_C64(0xD898263AFD2FD556), + SPH_C64(0xC8F4924DD80C8FD6), SPH_C64(0xCF99CA3D754A173A), + SPH_C64(0xFE477BACAF91BF3C), SPH_C64(0xED5371F6D690C12D), + SPH_C64(0x831A5C285E687094), SPH_C64(0xC5D3C90A3708A0A4), + SPH_C64(0x0F7F903717D06580), SPH_C64(0x19F9BB13B8FDF27F), + SPH_C64(0xB1BD6F1B4D502843), SPH_C64(0x1C761BA38FFF4012), + SPH_C64(0x0D1530C4E2E21F3B), SPH_C64(0x8943CE69A7372C8A), + SPH_C64(0xE5184E11FEB5CE66), SPH_C64(0x618BDB80BD736621), + SPH_C64(0x7D29BAD68B574D0B), SPH_C64(0x81BB613E25E6FE5B), + SPH_C64(0x071C9C10BC07913F), SPH_C64(0xC7BEEB7909AC2D97), + SPH_C64(0xC3E58D353BC5D757), SPH_C64(0xEB017892F38F61E8), + SPH_C64(0xD4EFFB9C9B1CC21A), SPH_C64(0x99727D26F494F7AB), + SPH_C64(0xA3E063A2956B3E03), SPH_C64(0x9D4A8B9A4AA09C30), + SPH_C64(0x3F6AB7D500090FB4), SPH_C64(0x9CC0F2A057268AC0), + SPH_C64(0x3DEE9D2DEDBF42D1), SPH_C64(0x330F49C87960A972), + SPH_C64(0xC6B2720287421B41), SPH_C64(0x0AC59EC07C00369C), + SPH_C64(0xEF4EAC49CB353425), SPH_C64(0xF450244EEF0129D8), + SPH_C64(0x8ACC46E5CAF4DEB6), SPH_C64(0x2FFEAB63989263F7), + SPH_C64(0x8F7CB9FE5D7A4578), SPH_C64(0x5BD8F7644E634635), + SPH_C64(0x427A7315BF2DC900), SPH_C64(0x17D0C4AA2125261C), + SPH_C64(0x3992486C93518E50), SPH_C64(0xB4CBFEE0A2D7D4C3), + SPH_C64(0x7C75D6202C5DDD8D), SPH_C64(0xDBC295D8E35B6C61), + SPH_C64(0x60B369D302032B19), SPH_C64(0xCE42685FDCE44132), + SPH_C64(0x06F3DDB9DDF65610), SPH_C64(0x8EA4D21DB5E148F0), + SPH_C64(0x20B0FCE62FCD496F), SPH_C64(0x2C1B912358B0EE31), + SPH_C64(0xB28317B818F5A308), SPH_C64(0xA89C1E189CA6D2CF), + SPH_C64(0x0C6B18576AAADBC8), SPH_C64(0xB65DEAA91299FAE3), + SPH_C64(0xFB2B794B7F1027E7), SPH_C64(0x04E4317F443B5BEB), + SPH_C64(0x4B852D325939D0A6), SPH_C64(0xD5AE6BEEFB207FFC), + SPH_C64(0x309682B281C7D374), SPH_C64(0xBAE309A194C3B475), + SPH_C64(0x8CC3F97B13B49F05), SPH_C64(0x98A9422FF8293967), + SPH_C64(0x244B16B01076FF7C), SPH_C64(0xF8BF571C663D67EE), + SPH_C64(0x1F0D6758EEE30DA1), SPH_C64(0xC9B611D97ADEB9B7), + SPH_C64(0xB7AFD5887B6C57A2), SPH_C64(0x6290AE846B984FE1), + SPH_C64(0x94DF4CDEACC1A5FD), SPH_C64(0x058A5BD1C5483AFF), + SPH_C64(0x63166CC142BA3C37), SPH_C64(0x8DB8526EB2F76F40), + SPH_C64(0xE10880036F0D6D4E), SPH_C64(0x9E0523C9971D311D), + SPH_C64(0x45EC2824CC7CD691), SPH_C64(0x575B8359E62382C9), + SPH_C64(0xFA9E400DC4889995), SPH_C64(0xD1823ECB45721568), + SPH_C64(0xDAFD983B8206082F), SPH_C64(0xAA7D29082386A8CB), + SPH_C64(0x269FCD4403B87588), SPH_C64(0x1B91F5F728BDD1E0), + SPH_C64(0xE4669F39040201F6), SPH_C64(0x7A1D7C218CF04ADE), + SPH_C64(0x65623C29D79CE5CE), SPH_C64(0x2368449096C00BB1), + SPH_C64(0xAB9BF1879DA503BA), SPH_C64(0xBC23ECB1A458058E), + SPH_C64(0x9A58DF01BB401ECC), SPH_C64(0xA070E868A85F143D), + SPH_C64(0x4FF188307DF2239E), SPH_C64(0x14D565B41A641183), + SPH_C64(0xEE13337452701602), SPH_C64(0x950E3DCF3F285E09), + SPH_C64(0x59930254B9C80953), SPH_C64(0x3BF299408930DA6D), + SPH_C64(0xA955943F53691387), SPH_C64(0xA15EDECAA9CB8784), + SPH_C64(0x29142127352BE9A0), SPH_C64(0x76F0371FFF4E7AFB), + SPH_C64(0x0239F450274F2228), SPH_C64(0xBB073AF01D5E868B), + SPH_C64(0xBFC80571C10E96C1), SPH_C64(0xD267088568222E23), + SPH_C64(0x9671A3D48E80B5B0), SPH_C64(0x55B5D38AE193BB81), + SPH_C64(0x693AE2D0A18B04B8), SPH_C64(0x5C48B4ECADD5335F), + SPH_C64(0xFD743B194916A1CA), SPH_C64(0x2577018134BE98C4), + SPH_C64(0xE77987E83C54A4AD), SPH_C64(0x28E11014DA33E1B9), + SPH_C64(0x270CC59E226AA213), SPH_C64(0x71495F756D1A5F60), + SPH_C64(0x9BE853FB60AFEF77), SPH_C64(0xADC786A7F7443DBF), + SPH_C64(0x0904456173B29A82), SPH_C64(0x58BC7A66C232BD5E), + SPH_C64(0xF306558C673AC8B2), SPH_C64(0x41F639C6B6C9772A), + SPH_C64(0x216DEFE99FDA35DA), SPH_C64(0x11640CC71C7BE615), + SPH_C64(0x93C43694565C5527), SPH_C64(0xEA038E6246777839), + SPH_C64(0xF9ABF3CE5A3E2469), SPH_C64(0x741E768D0FD312D2), + SPH_C64(0x0144B883CED652C6), SPH_C64(0xC20B5A5BA33F8552), + SPH_C64(0x1AE69633C3435A9D), SPH_C64(0x97A28CA4088CFDEC), + SPH_C64(0x8824A43C1E96F420), SPH_C64(0x37612FA66EEEA746), + SPH_C64(0x6B4CB165F9CF0E5A), SPH_C64(0x43AA1C06A0ABFB4A), + SPH_C64(0x7F4DC26FF162796B), SPH_C64(0x6CBACC8E54ED9B0F), + SPH_C64(0xA6B7FFEFD2BB253E), SPH_C64(0x2E25BC95B0A29D4F), + SPH_C64(0x86D6A58BDEF1388C), SPH_C64(0xDED74AC576B6F054), + SPH_C64(0x8030BDBC2B45805D), SPH_C64(0x3C81AF70E94D9289), + SPH_C64(0x3EFF6DDA9E3100DB), SPH_C64(0xB38DC39FDFCC8847), + SPH_C64(0x123885528D17B87E), SPH_C64(0xF2DA0ED240B1B642), + SPH_C64(0x44CEFADCD54BF9A9), SPH_C64(0x1312200E433C7EE6), + SPH_C64(0x9FFCC84F3A78C748), SPH_C64(0xF0CD1F72248576BB), + SPH_C64(0xEC6974053638CFE4), SPH_C64(0x2BA7B67C0CEC4E4C), + SPH_C64(0xAC2F4DF3E5CE32ED), SPH_C64(0xCB33D14326EA4C11), + SPH_C64(0xA4E9044CC77E58BC), SPH_C64(0x5F513293D934FCEF), + SPH_C64(0x5DC9645506E55444), SPH_C64(0x50DE418F317DE40A), + SPH_C64(0x388CB31A69DDE259), SPH_C64(0x2DB4A83455820A86), + SPH_C64(0x9010A91E84711AE9), SPH_C64(0x4DF7F0B7B1498371), + SPH_C64(0xD62A2EABC0977179), SPH_C64(0x22FAC097AA8D5C0E), +}; + +static const sph_u64 T3[256] = { + SPH_C64(0xF49FCC2FF1DAF39B), SPH_C64(0x487FD5C66FF29281), + SPH_C64(0xE8A30667FCDCA83F), SPH_C64(0x2C9B4BE3D2FCCE63), + SPH_C64(0xDA3FF74B93FBBBC2), SPH_C64(0x2FA165D2FE70BA66), + SPH_C64(0xA103E279970E93D4), SPH_C64(0xBECDEC77B0E45E71), + SPH_C64(0xCFB41E723985E497), SPH_C64(0xB70AAA025EF75017), + SPH_C64(0xD42309F03840B8E0), SPH_C64(0x8EFC1AD035898579), + SPH_C64(0x96C6920BE2B2ABC5), SPH_C64(0x66AF4163375A9172), + SPH_C64(0x2174ABDCCA7127FB), SPH_C64(0xB33CCEA64A72FF41), + SPH_C64(0xF04A4933083066A5), SPH_C64(0x8D970ACDD7289AF5), + SPH_C64(0x8F96E8E031C8C25E), SPH_C64(0xF3FEC02276875D47), + SPH_C64(0xEC7BF310056190DD), SPH_C64(0xF5ADB0AEBB0F1491), + SPH_C64(0x9B50F8850FD58892), SPH_C64(0x4975488358B74DE8), + SPH_C64(0xA3354FF691531C61), SPH_C64(0x0702BBE481D2C6EE), + SPH_C64(0x89FB24057DEDED98), SPH_C64(0xAC3075138596E902), + SPH_C64(0x1D2D3580172772ED), SPH_C64(0xEB738FC28E6BC30D), + SPH_C64(0x5854EF8F63044326), SPH_C64(0x9E5C52325ADD3BBE), + SPH_C64(0x90AA53CF325C4623), SPH_C64(0xC1D24D51349DD067), + SPH_C64(0x2051CFEEA69EA624), SPH_C64(0x13220F0A862E7E4F), + SPH_C64(0xCE39399404E04864), SPH_C64(0xD9C42CA47086FCB7), + SPH_C64(0x685AD2238A03E7CC), SPH_C64(0x066484B2AB2FF1DB), + SPH_C64(0xFE9D5D70EFBF79EC), SPH_C64(0x5B13B9DD9C481854), + SPH_C64(0x15F0D475ED1509AD), SPH_C64(0x0BEBCD060EC79851), + SPH_C64(0xD58C6791183AB7F8), SPH_C64(0xD1187C5052F3EEE4), + SPH_C64(0xC95D1192E54E82FF), SPH_C64(0x86EEA14CB9AC6CA2), + SPH_C64(0x3485BEB153677D5D), SPH_C64(0xDD191D781F8C492A), + SPH_C64(0xF60866BAA784EBF9), SPH_C64(0x518F643BA2D08C74), + SPH_C64(0x8852E956E1087C22), SPH_C64(0xA768CB8DC410AE8D), + SPH_C64(0x38047726BFEC8E1A), SPH_C64(0xA67738B4CD3B45AA), + SPH_C64(0xAD16691CEC0DDE19), SPH_C64(0xC6D4319380462E07), + SPH_C64(0xC5A5876D0BA61938), SPH_C64(0x16B9FA1FA58FD840), + SPH_C64(0x188AB1173CA74F18), SPH_C64(0xABDA2F98C99C021F), + SPH_C64(0x3E0580AB134AE816), SPH_C64(0x5F3B05B773645ABB), + SPH_C64(0x2501A2BE5575F2F6), SPH_C64(0x1B2F74004E7E8BA9), + SPH_C64(0x1CD7580371E8D953), SPH_C64(0x7F6ED89562764E30), + SPH_C64(0xB15926FF596F003D), SPH_C64(0x9F65293DA8C5D6B9), + SPH_C64(0x6ECEF04DD690F84C), SPH_C64(0x4782275FFF33AF88), + SPH_C64(0xE41433083F820801), SPH_C64(0xFD0DFE409A1AF9B5), + SPH_C64(0x4325A3342CDB396B), SPH_C64(0x8AE77E62B301B252), + SPH_C64(0xC36F9E9F6655615A), SPH_C64(0x85455A2D92D32C09), + SPH_C64(0xF2C7DEA949477485), SPH_C64(0x63CFB4C133A39EBA), + SPH_C64(0x83B040CC6EBC5462), SPH_C64(0x3B9454C8FDB326B0), + SPH_C64(0x56F56A9E87FFD78C), SPH_C64(0x2DC2940D99F42BC6), + SPH_C64(0x98F7DF096B096E2D), SPH_C64(0x19A6E01E3AD852BF), + SPH_C64(0x42A99CCBDBD4B40B), SPH_C64(0xA59998AF45E9C559), + SPH_C64(0x366295E807D93186), SPH_C64(0x6B48181BFAA1F773), + SPH_C64(0x1FEC57E2157A0A1D), SPH_C64(0x4667446AF6201AD5), + SPH_C64(0xE615EBCACFB0F075), SPH_C64(0xB8F31F4F68290778), + SPH_C64(0x22713ED6CE22D11E), SPH_C64(0x3057C1A72EC3C93B), + SPH_C64(0xCB46ACC37C3F1F2F), SPH_C64(0xDBB893FD02AAF50E), + SPH_C64(0x331FD92E600B9FCF), SPH_C64(0xA498F96148EA3AD6), + SPH_C64(0xA8D8426E8B6A83EA), SPH_C64(0xA089B274B7735CDC), + SPH_C64(0x87F6B3731E524A11), SPH_C64(0x118808E5CBC96749), + SPH_C64(0x9906E4C7B19BD394), SPH_C64(0xAFED7F7E9B24A20C), + SPH_C64(0x6509EADEEB3644A7), SPH_C64(0x6C1EF1D3E8EF0EDE), + SPH_C64(0xB9C97D43E9798FB4), SPH_C64(0xA2F2D784740C28A3), + SPH_C64(0x7B8496476197566F), SPH_C64(0x7A5BE3E6B65F069D), + SPH_C64(0xF96330ED78BE6F10), SPH_C64(0xEEE60DE77A076A15), + SPH_C64(0x2B4BEE4AA08B9BD0), SPH_C64(0x6A56A63EC7B8894E), + SPH_C64(0x02121359BA34FEF4), SPH_C64(0x4CBF99F8283703FC), + SPH_C64(0x398071350CAF30C8), SPH_C64(0xD0A77A89F017687A), + SPH_C64(0xF1C1A9EB9E423569), SPH_C64(0x8C7976282DEE8199), + SPH_C64(0x5D1737A5DD1F7ABD), SPH_C64(0x4F53433C09A9FA80), + SPH_C64(0xFA8B0C53DF7CA1D9), SPH_C64(0x3FD9DCBC886CCB77), + SPH_C64(0xC040917CA91B4720), SPH_C64(0x7DD00142F9D1DCDF), + SPH_C64(0x8476FC1D4F387B58), SPH_C64(0x23F8E7C5F3316503), + SPH_C64(0x032A2244E7E37339), SPH_C64(0x5C87A5D750F5A74B), + SPH_C64(0x082B4CC43698992E), SPH_C64(0xDF917BECB858F63C), + SPH_C64(0x3270B8FC5BF86DDA), SPH_C64(0x10AE72BB29B5DD76), + SPH_C64(0x576AC94E7700362B), SPH_C64(0x1AD112DAC61EFB8F), + SPH_C64(0x691BC30EC5FAA427), SPH_C64(0xFF246311CC327143), + SPH_C64(0x3142368E30E53206), SPH_C64(0x71380E31E02CA396), + SPH_C64(0x958D5C960AAD76F1), SPH_C64(0xF8D6F430C16DA536), + SPH_C64(0xC8FFD13F1BE7E1D2), SPH_C64(0x7578AE66004DDBE1), + SPH_C64(0x05833F01067BE646), SPH_C64(0xBB34B5AD3BFE586D), + SPH_C64(0x095F34C9A12B97F0), SPH_C64(0x247AB64525D60CA8), + SPH_C64(0xDCDBC6F3017477D1), SPH_C64(0x4A2E14D4DECAD24D), + SPH_C64(0xBDB5E6D9BE0A1EEB), SPH_C64(0x2A7E70F7794301AB), + SPH_C64(0xDEF42D8A270540FD), SPH_C64(0x01078EC0A34C22C1), + SPH_C64(0xE5DE511AF4C16387), SPH_C64(0x7EBB3A52BD9A330A), + SPH_C64(0x77697857AA7D6435), SPH_C64(0x004E831603AE4C32), + SPH_C64(0xE7A21020AD78E312), SPH_C64(0x9D41A70C6AB420F2), + SPH_C64(0x28E06C18EA1141E6), SPH_C64(0xD2B28CBD984F6B28), + SPH_C64(0x26B75F6C446E9D83), SPH_C64(0xBA47568C4D418D7F), + SPH_C64(0xD80BADBFE6183D8E), SPH_C64(0x0E206D7F5F166044), + SPH_C64(0xE258A43911CBCA3E), SPH_C64(0x723A1746B21DC0BC), + SPH_C64(0xC7CAA854F5D7CDD3), SPH_C64(0x7CAC32883D261D9C), + SPH_C64(0x7690C26423BA942C), SPH_C64(0x17E55524478042B8), + SPH_C64(0xE0BE477656A2389F), SPH_C64(0x4D289B5E67AB2DA0), + SPH_C64(0x44862B9C8FBBFD31), SPH_C64(0xB47CC8049D141365), + SPH_C64(0x822C1B362B91C793), SPH_C64(0x4EB14655FB13DFD8), + SPH_C64(0x1ECBBA0714E2A97B), SPH_C64(0x6143459D5CDE5F14), + SPH_C64(0x53A8FBF1D5F0AC89), SPH_C64(0x97EA04D81C5E5B00), + SPH_C64(0x622181A8D4FDB3F3), SPH_C64(0xE9BCD341572A1208), + SPH_C64(0x1411258643CCE58A), SPH_C64(0x9144C5FEA4C6E0A4), + SPH_C64(0x0D33D06565CF620F), SPH_C64(0x54A48D489F219CA1), + SPH_C64(0xC43E5EAC6D63C821), SPH_C64(0xA9728B3A72770DAF), + SPH_C64(0xD7934E7B20DF87EF), SPH_C64(0xE35503B61A3E86E5), + SPH_C64(0xCAE321FBC819D504), SPH_C64(0x129A50B3AC60BFA6), + SPH_C64(0xCD5E68EA7E9FB6C3), SPH_C64(0xB01C90199483B1C7), + SPH_C64(0x3DE93CD5C295376C), SPH_C64(0xAED52EDF2AB9AD13), + SPH_C64(0x2E60F512C0A07884), SPH_C64(0xBC3D86A3E36210C9), + SPH_C64(0x35269D9B163951CE), SPH_C64(0x0C7D6E2AD0CDB5FA), + SPH_C64(0x59E86297D87F5733), SPH_C64(0x298EF221898DB0E7), + SPH_C64(0x55000029D1A5AA7E), SPH_C64(0x8BC08AE1B5061B45), + SPH_C64(0xC2C31C2B6C92703A), SPH_C64(0x94CC596BAF25EF42), + SPH_C64(0x0A1D73DB22540456), SPH_C64(0x04B6A0F9D9C4179A), + SPH_C64(0xEFFDAFA2AE3D3C60), SPH_C64(0xF7C8075BB49496C4), + SPH_C64(0x9CC5C7141D1CD4E3), SPH_C64(0x78BD1638218E5534), + SPH_C64(0xB2F11568F850246A), SPH_C64(0xEDFABCFA9502BC29), + SPH_C64(0x796CE5F2DA23051B), SPH_C64(0xAAE128B0DC93537C), + SPH_C64(0x3A493DA0EE4B29AE), SPH_C64(0xB5DF6B2C416895D7), + SPH_C64(0xFCABBD25122D7F37), SPH_C64(0x70810B58105DC4B1), + SPH_C64(0xE10FDD37F7882A90), SPH_C64(0x524DCAB5518A3F5C), + SPH_C64(0x3C9E85878451255B), SPH_C64(0x4029828119BD34E2), + SPH_C64(0x74A05B6F5D3CECCB), SPH_C64(0xB610021542E13ECA), + SPH_C64(0x0FF979D12F59E2AC), SPH_C64(0x6037DA27E4F9CC50), + SPH_C64(0x5E92975A0DF1847D), SPH_C64(0xD66DE190D3E623FE), + SPH_C64(0x5032D6B87B568048), SPH_C64(0x9A36B7CE8235216E), + SPH_C64(0x80272A7A24F64B4A), SPH_C64(0x93EFED8B8C6916F7), + SPH_C64(0x37DDBFF44CCE1555), SPH_C64(0x4B95DB5D4B99BD25), + SPH_C64(0x92D3FDA169812FC0), SPH_C64(0xFB1A4A9A90660BB6), + SPH_C64(0x730C196946A4B9B2), SPH_C64(0x81E289AA7F49DA68), + SPH_C64(0x64669A0F83B1A05F), SPH_C64(0x27B3FF7D9644F48B), + SPH_C64(0xCC6B615C8DB675B3), SPH_C64(0x674F20B9BCEBBE95), + SPH_C64(0x6F31238275655982), SPH_C64(0x5AE488713E45CF05), + SPH_C64(0xBF619F9954C21157), SPH_C64(0xEABAC46040A8EAE9), + SPH_C64(0x454C6FE9F2C0C1CD), SPH_C64(0x419CF6496412691C), + SPH_C64(0xD3DC3BEF265B0F70), SPH_C64(0x6D0E60F5C3578A9E), +}; + +static const sph_u64 T4[256] = { + SPH_C64(0x5B0E608526323C55), SPH_C64(0x1A46C1A9FA1B59F5), + SPH_C64(0xA9E245A17C4C8FFA), SPH_C64(0x65CA5159DB2955D7), + SPH_C64(0x05DB0A76CE35AFC2), SPH_C64(0x81EAC77EA9113D45), + SPH_C64(0x528EF88AB6AC0A0D), SPH_C64(0xA09EA253597BE3FF), + SPH_C64(0x430DDFB3AC48CD56), SPH_C64(0xC4B3A67AF45CE46F), + SPH_C64(0x4ECECFD8FBE2D05E), SPH_C64(0x3EF56F10B39935F0), + SPH_C64(0x0B22D6829CD619C6), SPH_C64(0x17FD460A74DF2069), + SPH_C64(0x6CF8CC8E8510ED40), SPH_C64(0xD6C824BF3A6ECAA7), + SPH_C64(0x61243D581A817049), SPH_C64(0x048BACB6BBC163A2), + SPH_C64(0xD9A38AC27D44CC32), SPH_C64(0x7FDDFF5BAAF410AB), + SPH_C64(0xAD6D495AA804824B), SPH_C64(0xE1A6A74F2D8C9F94), + SPH_C64(0xD4F7851235DEE8E3), SPH_C64(0xFD4B7F886540D893), + SPH_C64(0x247C20042AA4BFDA), SPH_C64(0x096EA1C517D1327C), + SPH_C64(0xD56966B4361A6685), SPH_C64(0x277DA5C31221057D), + SPH_C64(0x94D59893A43ACFF7), SPH_C64(0x64F0C51CCDC02281), + SPH_C64(0x3D33BCC4FF6189DB), SPH_C64(0xE005CB184CE66AF1), + SPH_C64(0xFF5CCD1D1DB99BEA), SPH_C64(0xB0B854A7FE42980F), + SPH_C64(0x7BD46A6A718D4B9F), SPH_C64(0xD10FA8CC22A5FD8C), + SPH_C64(0xD31484952BE4BD31), SPH_C64(0xC7FA975FCB243847), + SPH_C64(0x4886ED1E5846C407), SPH_C64(0x28CDDB791EB70B04), + SPH_C64(0xC2B00BE2F573417F), SPH_C64(0x5C9590452180F877), + SPH_C64(0x7A6BDDFFF370EB00), SPH_C64(0xCE509E38D6D9D6A4), + SPH_C64(0xEBEB0F00647FA702), SPH_C64(0x1DCC06CF76606F06), + SPH_C64(0xE4D9F28BA286FF0A), SPH_C64(0xD85A305DC918C262), + SPH_C64(0x475B1D8732225F54), SPH_C64(0x2D4FB51668CCB5FE), + SPH_C64(0xA679B9D9D72BBA20), SPH_C64(0x53841C0D912D43A5), + SPH_C64(0x3B7EAA48BF12A4E8), SPH_C64(0x781E0E47F22F1DDF), + SPH_C64(0xEFF20CE60AB50973), SPH_C64(0x20D261D19DFFB742), + SPH_C64(0x16A12B03062A2E39), SPH_C64(0x1960EB2239650495), + SPH_C64(0x251C16FED50EB8B8), SPH_C64(0x9AC0C330F826016E), + SPH_C64(0xED152665953E7671), SPH_C64(0x02D63194A6369570), + SPH_C64(0x5074F08394B1C987), SPH_C64(0x70BA598C90B25CE1), + SPH_C64(0x794A15810B9742F6), SPH_C64(0x0D5925E9FCAF8C6C), + SPH_C64(0x3067716CD868744E), SPH_C64(0x910AB077E8D7731B), + SPH_C64(0x6A61BBDB5AC42F61), SPH_C64(0x93513EFBF0851567), + SPH_C64(0xF494724B9E83E9D5), SPH_C64(0xE887E1985C09648D), + SPH_C64(0x34B1D3C675370CFD), SPH_C64(0xDC35E433BC0D255D), + SPH_C64(0xD0AAB84234131BE0), SPH_C64(0x08042A50B48B7EAF), + SPH_C64(0x9997C4EE44A3AB35), SPH_C64(0x829A7B49201799D0), + SPH_C64(0x263B8307B7C54441), SPH_C64(0x752F95F4FD6A6CA6), + SPH_C64(0x927217402C08C6E5), SPH_C64(0x2A8AB754A795D9EE), + SPH_C64(0xA442F7552F72943D), SPH_C64(0x2C31334E19781208), + SPH_C64(0x4FA98D7CEAEE6291), SPH_C64(0x55C3862F665DB309), + SPH_C64(0xBD0610175D53B1F3), SPH_C64(0x46FE6CB840413F27), + SPH_C64(0x3FE03792DF0CFA59), SPH_C64(0xCFE700372EB85E8F), + SPH_C64(0xA7BE29E7ADBCE118), SPH_C64(0xE544EE5CDE8431DD), + SPH_C64(0x8A781B1B41F1873E), SPH_C64(0xA5C94C78A0D2F0E7), + SPH_C64(0x39412E2877B60728), SPH_C64(0xA1265EF3AFC9A62C), + SPH_C64(0xBCC2770C6A2506C5), SPH_C64(0x3AB66DD5DCE1CE12), + SPH_C64(0xE65499D04A675B37), SPH_C64(0x7D8F523481BFD216), + SPH_C64(0x0F6F64FCEC15F389), SPH_C64(0x74EFBE618B5B13C8), + SPH_C64(0xACDC82B714273E1D), SPH_C64(0xDD40BFE003199D17), + SPH_C64(0x37E99257E7E061F8), SPH_C64(0xFA52626904775AAA), + SPH_C64(0x8BBBF63A463D56F9), SPH_C64(0xF0013F1543A26E64), + SPH_C64(0xA8307E9F879EC898), SPH_C64(0xCC4C27A4150177CC), + SPH_C64(0x1B432F2CCA1D3348), SPH_C64(0xDE1D1F8F9F6FA013), + SPH_C64(0x606602A047A7DDD6), SPH_C64(0xD237AB64CC1CB2C7), + SPH_C64(0x9B938E7225FCD1D3), SPH_C64(0xEC4E03708E0FF476), + SPH_C64(0xFEB2FBDA3D03C12D), SPH_C64(0xAE0BCED2EE43889A), + SPH_C64(0x22CB8923EBFB4F43), SPH_C64(0x69360D013CF7396D), + SPH_C64(0x855E3602D2D4E022), SPH_C64(0x073805BAD01F784C), + SPH_C64(0x33E17A133852F546), SPH_C64(0xDF4874058AC7B638), + SPH_C64(0xBA92B29C678AA14A), SPH_C64(0x0CE89FC76CFAADCD), + SPH_C64(0x5F9D4E0908339E34), SPH_C64(0xF1AFE9291F5923B9), + SPH_C64(0x6E3480F60F4A265F), SPH_C64(0xEEBF3A2AB29B841C), + SPH_C64(0xE21938A88F91B4AD), SPH_C64(0x57DFEFF845C6D3C3), + SPH_C64(0x2F006B0BF62CAAF2), SPH_C64(0x62F479EF6F75EE78), + SPH_C64(0x11A55AD41C8916A9), SPH_C64(0xF229D29084FED453), + SPH_C64(0x42F1C27B16B000E6), SPH_C64(0x2B1F76749823C074), + SPH_C64(0x4B76ECA3C2745360), SPH_C64(0x8C98F463B91691BD), + SPH_C64(0x14BCC93CF1ADE66A), SPH_C64(0x8885213E6D458397), + SPH_C64(0x8E177DF0274D4711), SPH_C64(0xB49B73B5503F2951), + SPH_C64(0x10168168C3F96B6B), SPH_C64(0x0E3D963B63CAB0AE), + SPH_C64(0x8DFC4B5655A1DB14), SPH_C64(0xF789F1356E14DE5C), + SPH_C64(0x683E68AF4E51DAC1), SPH_C64(0xC9A84F9D8D4B0FD9), + SPH_C64(0x3691E03F52A0F9D1), SPH_C64(0x5ED86E46E1878E80), + SPH_C64(0x3C711A0E99D07150), SPH_C64(0x5A0865B20C4E9310), + SPH_C64(0x56FBFC1FE4F0682E), SPH_C64(0xEA8D5DE3105EDF9B), + SPH_C64(0x71ABFDB12379187A), SPH_C64(0x2EB99DE1BEE77B9C), + SPH_C64(0x21ECC0EA33CF4523), SPH_C64(0x59A4D7521805C7A1), + SPH_C64(0x3896F5EB56AE7C72), SPH_C64(0xAA638F3DB18F75DC), + SPH_C64(0x9F39358DABE9808E), SPH_C64(0xB7DEFA91C00B72AC), + SPH_C64(0x6B5541FD62492D92), SPH_C64(0x6DC6DEE8F92E4D5B), + SPH_C64(0x353F57ABC4BEEA7E), SPH_C64(0x735769D6DA5690CE), + SPH_C64(0x0A234AA642391484), SPH_C64(0xF6F9508028F80D9D), + SPH_C64(0xB8E319A27AB3F215), SPH_C64(0x31AD9C1151341A4D), + SPH_C64(0x773C22A57BEF5805), SPH_C64(0x45C7561A07968633), + SPH_C64(0xF913DA9E249DBE36), SPH_C64(0xDA652D9B78A64C68), + SPH_C64(0x4C27A97F3BC334EF), SPH_C64(0x76621220E66B17F4), + SPH_C64(0x967743899ACD7D0B), SPH_C64(0xF3EE5BCAE0ED6782), + SPH_C64(0x409F753600C879FC), SPH_C64(0x06D09A39B5926DB6), + SPH_C64(0x6F83AEB0317AC588), SPH_C64(0x01E6CA4A86381F21), + SPH_C64(0x66FF3462D19F3025), SPH_C64(0x72207C24DDFD3BFB), + SPH_C64(0x4AF6B6D3E2ECE2EB), SPH_C64(0x9C994DBEC7EA08DE), + SPH_C64(0x49ACE597B09A8BC4), SPH_C64(0xB38C4766CF0797BA), + SPH_C64(0x131B9373C57C2A75), SPH_C64(0xB1822CCE61931E58), + SPH_C64(0x9D7555B909BA1C0C), SPH_C64(0x127FAFDD937D11D2), + SPH_C64(0x29DA3BADC66D92E4), SPH_C64(0xA2C1D57154C2ECBC), + SPH_C64(0x58C5134D82F6FE24), SPH_C64(0x1C3AE3515B62274F), + SPH_C64(0xE907C82E01CB8126), SPH_C64(0xF8ED091913E37FCB), + SPH_C64(0x3249D8F9C80046C9), SPH_C64(0x80CF9BEDE388FB63), + SPH_C64(0x1881539A116CF19E), SPH_C64(0x5103F3F76BD52457), + SPH_C64(0x15B7E6F5AE47F7A8), SPH_C64(0xDBD7C6DED47E9CCF), + SPH_C64(0x44E55C410228BB1A), SPH_C64(0xB647D4255EDB4E99), + SPH_C64(0x5D11882BB8AAFC30), SPH_C64(0xF5098BBB29D3212A), + SPH_C64(0x8FB5EA14E90296B3), SPH_C64(0x677B942157DD025A), + SPH_C64(0xFB58E7C0A390ACB5), SPH_C64(0x89D3674C83BD4A01), + SPH_C64(0x9E2DA4DF4BF3B93B), SPH_C64(0xFCC41E328CAB4829), + SPH_C64(0x03F38C96BA582C52), SPH_C64(0xCAD1BDBD7FD85DB2), + SPH_C64(0xBBB442C16082AE83), SPH_C64(0xB95FE86BA5DA9AB0), + SPH_C64(0xB22E04673771A93F), SPH_C64(0x845358C9493152D8), + SPH_C64(0xBE2A488697B4541E), SPH_C64(0x95A2DC2DD38E6966), + SPH_C64(0xC02C11AC923C852B), SPH_C64(0x2388B1990DF2A87B), + SPH_C64(0x7C8008FA1B4F37BE), SPH_C64(0x1F70D0C84D54E503), + SPH_C64(0x5490ADEC7ECE57D4), SPH_C64(0x002B3C27D9063A3A), + SPH_C64(0x7EAEA3848030A2BF), SPH_C64(0xC602326DED2003C0), + SPH_C64(0x83A7287D69A94086), SPH_C64(0xC57A5FCB30F57A8A), + SPH_C64(0xB56844E479EBE779), SPH_C64(0xA373B40F05DCBCE9), + SPH_C64(0xD71A786E88570EE2), SPH_C64(0x879CBACDBDE8F6A0), + SPH_C64(0x976AD1BCC164A32F), SPH_C64(0xAB21E25E9666D78B), + SPH_C64(0x901063AAE5E5C33C), SPH_C64(0x9818B34448698D90), + SPH_C64(0xE36487AE3E1E8ABB), SPH_C64(0xAFBDF931893BDCB4), + SPH_C64(0x6345A0DC5FBBD519), SPH_C64(0x8628FE269B9465CA), + SPH_C64(0x1E5D01603F9C51EC), SPH_C64(0x4DE44006A15049B7), + SPH_C64(0xBF6C70E5F776CBB1), SPH_C64(0x411218F2EF552BED), + SPH_C64(0xCB0C0708705A36A3), SPH_C64(0xE74D14754F986044), + SPH_C64(0xCD56D9430EA8280E), SPH_C64(0xC12591D7535F5065), + SPH_C64(0xC83223F1720AEF96), SPH_C64(0xC3A0396F7363A51F), +}; + +#define PASS(a, b, c, mul) do { \ + ROUND(a, b, c, X0, mul); \ + ROUND(b, c, a, X1, mul); \ + ROUND(c, a, b, X2, mul); \ + ROUND(a, b, c, X3, mul); \ + ROUND(b, c, a, X4, mul); \ + ROUND(c, a, b, X5, mul); \ + ROUND(a, b, c, X6, mul); \ + ROUND(b, c, a, X7, mul); \ + } while (0) + +#define ROUND(a, b, c, x, mul) do { \ + c ^= x; \ + a = SPH_T64(a - (T1[c & 0xFF] ^ T2[(c >> 16) & 0xFF] \ + ^ T3[(c >> 32) & 0xFF] ^ T4[(c >> 48) & 0xFF])); \ + b = SPH_T64(b + (T4[(c >> 8) & 0xFF] ^ T3[(c >> 24) & 0xFF] \ + ^ T2[(c >> 40) & 0xFF] ^ T1[(c >> 56) & 0xFF])); \ + b = mul(b); \ + } while (0) + +#define MUL5(x) SPH_T64((x) * SPH_C64(5)) +#define MUL7(x) SPH_T64((x) * SPH_C64(7)) +#define MUL9(x) SPH_T64((x) * SPH_C64(9)) + +#define KSCHED do { \ + X0 = SPH_T64(X0 - (X7 ^ SPH_C64(0xA5A5A5A5A5A5A5A5))); \ + X1 ^= X0; \ + X2 = SPH_T64(X2 + X1); \ + X3 = SPH_T64(X3 - (X2 ^ (~X1 << 19))); \ + X4 ^= X3; \ + X5 = SPH_T64(X5 + X4); \ + X6 = SPH_T64(X6 - (X5 ^ (~X4 >> 23))); \ + X7 ^= X6; \ + X0 = SPH_T64(X0 + X7); \ + X1 = SPH_T64(X1 - (X0 ^ (~X7 << 19))); \ + X2 ^= X1; \ + X3 = SPH_T64(X3 + X2); \ + X4 = SPH_T64(X4 - (X3 ^ (~X2 >> 23))); \ + X5 ^= X4; \ + X6 = SPH_T64(X6 + X5); \ + X7 = SPH_T64(X7 - (X6 ^ SPH_C64(0x0123456789ABCDEF))); \ + } while (0) + +#define TIGER_ROUND_BODY(in, r) do { \ + sph_u64 A, B, C; \ + sph_u64 X0, X1, X2, X3, X4, X5, X6, X7; \ + \ + A = (r)[0]; \ + B = (r)[1]; \ + C = (r)[2]; \ + \ + X0 = (in(0)); \ + X1 = (in(1)); \ + X2 = (in(2)); \ + X3 = (in(3)); \ + X4 = (in(4)); \ + X5 = (in(5)); \ + X6 = (in(6)); \ + X7 = (in(7)); \ + PASS(A, B, C, MUL5); \ + KSCHED; \ + PASS(C, A, B, MUL7); \ + KSCHED; \ + PASS(B, C, A, MUL9); \ + \ + (r)[0] ^= A; \ + (r)[1] = SPH_T64(B - (r)[1]); \ + (r)[2] = SPH_T64(C + (r)[2]); \ + } while (0) + +/* + * One round of Tiger. The data must be aligned for 64-bit access. + */ +static void +tiger_round(const unsigned char *data, sph_u64 r[3]) +{ +#define TIGER_IN(i) sph_dec64le_aligned(data + 8 * (i)) + TIGER_ROUND_BODY(TIGER_IN, r); +#undef TIGER_IN +} + +/* see sph_tiger.h */ +void +sph_tiger_init(void *cc) +{ + sph_tiger_context *sc; + + sc = (sph_tiger_context*)cc; + sc->val[0] = SPH_C64(0x0123456789ABCDEF); + sc->val[1] = SPH_C64(0xFEDCBA9876543210); + sc->val[2] = SPH_C64(0xF096A5B4C3B2E187); + sc->count = 0; +} + +#define RFUN tiger_round +#define HASH tiger +#define LE64 1 +#define BLEN 64U +#define PW01 1 +#define PLW1 1 +#include "md_helper.c" + +/* see sph_tiger.h */ +void +sph_tiger_close(void *cc, void *dst) +{ + tiger_close(cc, dst, 3); + sph_tiger_init(cc); +} + +/* see sph_tiger.h */ +void +sph_tiger_comp(const sph_u64 msg[8], sph_u64 val[3]) +{ +#define TIGER_IN(i) msg[i] + TIGER_ROUND_BODY(TIGER_IN, val); +#undef TIGER_IN +} + +#undef HASH +#define HASH tiger2 +#undef PW01 +#define CLOSE_ONLY 1 +#include "md_helper.c" + +/* see sph_tiger.h */ +void +sph_tiger2_close(void *cc, void *dst) +{ + tiger2_close(cc, dst, 3); + sph_tiger2_init(cc); +} + +#endif diff --git a/sha3/sph_tiger.h b/sha3/sph_tiger.h new file mode 100644 index 000000000..10191f3db --- /dev/null +++ b/sha3/sph_tiger.h @@ -0,0 +1,191 @@ +/* $Id: sph_tiger.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * Tiger / Tiger-2 interface. + * + * Tiger has been published in: R. Anderson, E. Biham, "Tiger: A Fast + * New Hash Function", Fast Software Encryption - FSE'96, LNCS 1039, + * Springer (1996), pp. 89--97. + * + * Tiger2 has never been formally published, but it was described as + * identical to Tiger, except for the padding which is the same in + * Tiger2 as it is in MD4. Fortunately, an implementation of Tiger2 + * was submitted to NESSIE, which produced test vectors; the sphlib + * implementation of Tiger2 is compatible with the NESSIE test vectors. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_tiger.h + * @author Thomas Pornin + */ + +#ifndef SPH_TIGER_H__ +#define SPH_TIGER_H__ + +#include +#include "sph_types.h" + +#if SPH_64 + +/** + * Output size (in bits) for Tiger. + */ +#define SPH_SIZE_tiger 192 + +/** + * Output size (in bits) for Tiger2. + */ +#define SPH_SIZE_tiger2 192 + +/** + * This structure is a context for Tiger computations: it contains the + * intermediate values and some data from the last entered block. Once + * a Tiger computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running Tiger computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + sph_u64 val[3]; + sph_u64 count; +#endif +} sph_tiger_context; + +/** + * Initialize a Tiger context. This process performs no memory allocation. + * + * @param cc the Tiger context (pointer to + * a sph_tiger_context) + */ +void sph_tiger_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Tiger context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_tiger(void *cc, const void *data, size_t len); + +/** + * Terminate the current Tiger computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (24 bytes). The context is automatically + * reinitialized. + * + * @param cc the Tiger context + * @param dst the destination buffer + */ +void sph_tiger_close(void *cc, void *dst); + +/** + * Apply the Tiger compression function on the provided data. The + * msg parameter contains the 8 64-bit input blocks, + * as numerical values (hence after the little-endian decoding). The + * val parameter contains the 3 64-bit input blocks for + * the compression function; the output is written in place in this + * array. + * + * @param msg the message block (8 values) + * @param val the function 192-bit input and output + */ +void sph_tiger_comp(const sph_u64 msg[8], sph_u64 val[3]); + +/** + * This structure is a context for Tiger2 computations. It is identical + * to the Tiger context, and they may be freely exchanged, since the + * difference between Tiger and Tiger2 resides solely in the padding, which + * is computed only in the last computation step. + */ +typedef sph_tiger_context sph_tiger2_context; + +#ifdef DOXYGEN_IGNORE +/** + * Initialize a Tiger2 context. This function is identical to + * sph_tiger_init(). + * + * @param cc the Tiger2 context (pointer to + * a sph_tiger2_context) + */ +void sph_tiger2_init(void *cc); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_tiger2_init sph_tiger_init +#endif + +#ifdef DOXYGEN_IGNORE +/** + * Process some data bytes. This function is identical to + * sph_tiger(). + * + * @param cc the Tiger2 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_tiger2(void *cc, const void *data, size_t len); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_tiger2 sph_tiger +#endif + +/** + * Terminate the current Tiger2 computation and output the result into the + * provided buffer. The destination buffer must be wide enough to + * accomodate the result (24 bytes). The context is automatically + * reinitialized. Note that this function is NOT identical to + * sph_tiger2_close(): this is the exact and unique point + * where Tiger and Tiger2 differ. + * + * @param cc the Tiger context + * @param dst the destination buffer + */ +void sph_tiger2_close(void *cc, void *dst); + +#ifdef DOXYGEN_IGNORE +/** + * Apply the Tiger2 compression function, which is identical to the Tiger + * compression function. + * + * @param msg the message block (8 values) + * @param val the function 192-bit input and output + */ +void sph_tiger2_comp(const sph_u64 msg[8], sph_u64 val[3]); +#endif + +#ifndef DOXYGEN_IGNORE +#define sph_tiger2_comp sph_tiger_comp +#endif + +#endif + +#endif diff --git a/sha3/sph_types.h b/sha3/sph_types.h index 7295b0b37..6c8ecf4b6 100644 --- a/sha3/sph_types.h +++ b/sha3/sph_types.h @@ -930,14 +930,24 @@ typedef long long sph_s64; */ #define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) +#ifdef _MSC_VER +#define SPH_ROTL32(x, n) _rotl(x, n) +#define SPH_ROTR32(x, n) _rotr(x, n) +#else #define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) #define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) +#endif #if SPH_64 #define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) +#ifdef _MSC_VER +#define SPH_ROTL64(x, n) _rotl64(x, n) +#define SPH_ROTR64(x, n) _rotr64(x, n) +#else #define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) #define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) +#endif #endif diff --git a/sha3/sph_whirlpool.c b/sha3/sph_whirlpool.c index e66384f45..07ff50cbd 100644 --- a/sha3/sph_whirlpool.c +++ b/sha3/sph_whirlpool.c @@ -3432,7 +3432,7 @@ ROUND_FUN(whirlpool1, old1) * We want big-endian encoding of the message length, over 256 bits. BE64 * triggers that. However, our block length is 512 bits, not 1024 bits. * Internally, our encoding/decoding is little-endian, which is not a - * problem here since we also deactivate output in sph_x15_helper.c. + * problem here since we also deactivate output in md_helper.c. */ #define BE64 1 #define SVAL sc->state @@ -3441,19 +3441,19 @@ ROUND_FUN(whirlpool1, old1) #define RFUN whirlpool_round #define HASH whirlpool -#include "sph_x15_helper.c" +#include "md_helper.c" #undef RFUN #undef HASH #define RFUN whirlpool0_round #define HASH whirlpool0 -#include "sph_x15_helper.c" +#include "md_helper.c" #undef RFUN #undef HASH #define RFUN whirlpool1_round #define HASH whirlpool1 -#include "sph_x15_helper.c" +#include "md_helper.c" #undef RFUN #undef HASH @@ -3477,4 +3477,4 @@ MAKE_CLOSE(whirlpool1) #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/skein.c b/skein.c deleted file mode 100644 index 735dfb3d6..000000000 --- a/skein.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "cpuminer-config.h" -#include "miner.h" - -#include -#include - -#include - -#include "sha3/sph_skein.h" - -static void skeinhash(void *state, const void *input) -{ - sph_skein512_context ctx_skein; - static unsigned char pblank[1]; - - uint32_t mask = 8; - uint32_t zero = 0; - - //these uint512 in the c++ source of the client are backed by an array of uint32 - uint32_t hashA[16], hashB[16]; - - sph_skein512_init(&ctx_skein); - sph_skein512 (&ctx_skein, input, 80); //6 - sph_skein512_close(&ctx_skein, hashA); //7 - - SHA256_CTX sha256; - SHA256_Init(&sha256); - SHA256_Update(&sha256, hashA, 64); - SHA256_Final((unsigned char*) hashB, &sha256); - - memcpy(state, hashB, 32); - - -/* int ii; - printf("result: "); - for (ii=0; ii < 32; ii++) - { - printf ("%.2x",((uint8_t*)state)[ii]); - }; - printf ("\n"); -*/ -} - -int scanhash_skein(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t n = pdata[19] - 1; - const uint32_t first_nonce = pdata[19]; - const uint32_t Htarg = ptarget[7]; - - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - - //char testdata[] = {"\x70\x00\x00\x00\x5d\x38\x5b\xa1\x14\xd0\x79\x97\x0b\x29\xa9\x41\x8f\xd0\x54\x9e\x7d\x68\xa9\x5c\x7f\x16\x86\x21\xa3\x14\x20\x10\x00\x00\x00\x00\x57\x85\x86\xd1\x49\xfd\x07\xb2\x2f\x3a\x8a\x34\x7c\x51\x6d\xe7\x05\x2f\x03\x4d\x2b\x76\xff\x68\xe0\xd6\xec\xff\x9b\x77\xa4\x54\x89\xe3\xfd\x51\x17\x32\x01\x1d\xf0\x73\x10\x00"}; - - //we need bigendian data... - //lessons learned: do NOT endianchange directly in pdata, this will all proof-of-works be considered as stale from minerd.... - int kk=0; - for (; kk < 32; kk++) - { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; - - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - skeinhash(hash64, &endiandata); - if (((hash64[7]&0xFFFFFF00)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - *hashes_done = n - first_nonce + 1; - pdata[19] = n; - return 0; -} \ No newline at end of file diff --git a/sysinfos.c b/sysinfos.c new file mode 100644 index 000000000..3b6c5811b --- /dev/null +++ b/sysinfos.c @@ -0,0 +1,290 @@ +/** + * Unit to read cpu informations + * + * tpruvot 2014 + */ + +#include +#include +#include +#include + +#include "miner.h" + +#ifndef WIN32 + +#define HWMON_PATH \ + "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp1_input" +#define HWMON_ALT \ + "/sys/class/hwmon/hwmon1/temp1_input" +#define HWMON_ALT2 \ + "/sys/class/hwmon/hwmon0/temp1_input" +#define HWMON_ALT3 \ + "/sys/devices/platform/coretemp.0/hwmon/hwmon0/temp2_input" +#define HWMON_ALT4 \ + "/sys/class/hwmon/hwmon0/temp2_input" +#define HWMON_ALT5 \ + "/sys/class/hwmon/hwmon0/device/temp1_input" +#define HWMON_ALT6 \ + "/sys/class/thermal/thermal_zone0/temp" + +static float linux_cputemp(int core) +{ + float tc = 0.0; + FILE *fd = fopen(HWMON_PATH, "r"); + uint32_t val = 0; + + if (!fd) + fd = fopen(HWMON_ALT, "r"); + + if (!fd) + fd = fopen(HWMON_ALT2, "r"); + + if (!fd) + fd = fopen(HWMON_ALT3, "r"); + + if (!fd) + fd = fopen(HWMON_ALT4, "r"); + + if (!fd) + fd = fopen(HWMON_ALT5, "r"); + + if (!fd) + fd = fopen(HWMON_ALT6, "r"); + + if (!fd) + return tc; + + if (fscanf(fd, "%d", &val)) + tc = val / 1000.0; + + fclose(fd); + return tc; +} + +#define CPUFREQ_PATH \ + "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq" +static uint32_t linux_cpufreq(int core) +{ + FILE *fd = fopen(CPUFREQ_PATH, "r"); + uint32_t freq = 0; + + if (!fd) + return freq; + + if (!fscanf(fd, "%d", &freq)) + return freq; + + fclose(fd); + return freq; +} + +#else /* WIN32 */ + +static float win32_cputemp(int core) +{ + // todo + return 0.0; +} + +#endif /* !WIN32 */ + + +/* exports */ + + +float cpu_temp(int core) +{ +#ifdef WIN32 + return win32_cputemp(core); +#else + return linux_cputemp(core); +#endif +} + +uint32_t cpu_clock(int core) +{ +#ifdef WIN32 + return 0; +#else + return linux_cpufreq(core); +#endif +} + +int cpu_fanpercent() +{ + return 0; +} + +#if !defined(__arm__) && !defined(__aarch64__) +static inline void cpuid(int functionnumber, int output[4]) { +#ifdef _MSC_VER + // Microsoft compiler, intrin.h included + __cpuidex(output, functionnumber, 0); +#elif defined(__INTEL_COMPILER) + __cpuid(output, functionnumber); +#elif defined(__GNUC__) || defined(__clang__) + // use inline assembly, Gnu/AT&T syntax + int a, b, c, d; + asm volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(functionnumber), "c"(0)); + output[0] = a; + output[1] = b; + output[2] = c; + output[3] = d; +#else + // unknown platform. try inline assembly with masm/intel syntax + __asm { + mov eax, functionnumber + xor ecx, ecx + cpuid; + mov esi, output + mov[esi], eax + mov[esi + 4], ebx + mov[esi + 8], ecx + mov[esi + 12], edx + } +#endif +} +#else /* !__arm__ */ +#define cpuid(fn, out) out[0] = 0; +#endif + +// For the i7-5775C will output : Intel(R) Core(TM) i7-5775C CPU @ 3.30GHz +void cpu_getname(char *outbuf, size_t maxsz) +{ + memset(outbuf, 0, maxsz); +#ifdef WIN32 + char brand[0xC0] = { 0 }; + int output[4] = { 0 }, ext; + cpuid(0x80000000, output); + ext = output[0]; + if (ext >= 0x80000004) { + for (int i = 2; i <= (ext & 0xF); i++) { + cpuid(0x80000000+i, output); + memcpy(&brand[(i-2) * 4*sizeof(int)], output, 4*sizeof(int)); + } + snprintf(outbuf, maxsz, "%s", brand); + } else { + // Fallback, for the i7-5775C will output + // Intel64 Family 6 Model 71 Stepping 1, GenuineIntel + snprintf(outbuf, maxsz, "%s", getenv("PROCESSOR_IDENTIFIER")); + } +#else + // Intel(R) Xeon(R) CPU E3-1245 V2 @ 3.40GHz + FILE *fd = fopen("/proc/cpuinfo", "rb"); + char *buf = NULL, *p, *eol; + size_t size = 0; + if (!fd) return; + while(getdelim(&buf, &size, 0, fd) != -1) { + if (buf && (p = strstr(buf, "model name\t")) && strstr(p, ":")) { + p = strstr(p, ":"); + if (p) { + p += 2; + eol = strstr(p, "\n"); if (eol) *eol = '\0'; + snprintf(outbuf, maxsz, "%s", p); + } + break; + } + } + free(buf); + fclose(fd); +#endif +} + +void cpu_getmodelid(char *outbuf, size_t maxsz) +{ + memset(outbuf, 0, maxsz); +#ifdef WIN32 + // For the i7-5775C will output 6:4701:8 + snprintf(outbuf, maxsz, "%s:%s:%s", getenv("PROCESSOR_LEVEL"), // hexa ? + getenv("PROCESSOR_REVISION"), getenv("NUMBER_OF_PROCESSORS")); +#else + FILE *fd = fopen("/proc/cpuinfo", "rb"); + char *buf = NULL, *p, *eol; + int cpufam = 0, model = 0, stepping = 0; + size_t size = 0; + if (!fd) return; + while(getdelim(&buf, &size, 0, fd) != -1) { + if (buf && (p = strstr(buf, "cpu family\t")) && strstr(p, ":")) { + p = strstr(p, ":"); + if (p) { + p += 2; + cpufam = atoi(p); + } + } + if (buf && (p = strstr(buf, "model\t")) && strstr(p, ":")) { + p = strstr(p, ":"); + if (p) { + p += 2; + model = atoi(p); + } + } + if (buf && (p = strstr(buf, "stepping\t")) && strstr(p, ":")) { + p = strstr(p, ":"); + if (p) { + p += 2; + stepping = atoi(p); + } + } + if (cpufam && model && stepping) { + snprintf(outbuf, maxsz, "%x:%02x%02x:%d", cpufam, model, stepping, num_cpus); + outbuf[maxsz-1] = '\0'; + break; + } + } + free(buf); + fclose(fd); +#endif +} + +// http://en.wikipedia.org/wiki/CPUID +#define OSXSAVE_Flag (1 << 27) +#define AVX1_Flag ((1 << 28)|OSXSAVE_Flag) +#define XOP_Flag (1 << 11) +#define FMA3_Flag ((1 << 12)|AVX1_Flag|OSXSAVE_Flag) +#define AES_Flag (1 << 25) +#define SSE42_Flag (1 << 20) + +#define SSE_Flag (1 << 25) // EDX +#define SSE2_Flag (1 << 26) // EDX + +#define AVX2_Flag (1 << 5) // ADV EBX + +bool has_aes_ni() +{ +#if defined(__arm__) || defined(__aarch64__) + return false; +#else + int cpu_info[4] = { 0 }; + cpuid(1, cpu_info); + return cpu_info[2] & AES_Flag; +#endif +} + +void cpu_bestfeature(char *outbuf, size_t maxsz) +{ +#if defined(__arm__) || defined(__aarch64__) + sprintf(outbuf, "ARM"); +#else + int cpu_info[4] = { 0 }; + int cpu_info_adv[4] = { 0 }; + cpuid(1, cpu_info); + cpuid(7, cpu_info_adv); + if ((cpu_info[2] & AVX1_Flag) && (cpu_info_adv[1] & AVX2_Flag)) + sprintf(outbuf, "AVX2"); + else if (cpu_info[2] & AVX1_Flag) + sprintf(outbuf, "AVX"); + else if (cpu_info[2] & FMA3_Flag) + sprintf(outbuf, "FMA3"); + else if (cpu_info[2] & XOP_Flag) + sprintf(outbuf, "XOP"); + else if (cpu_info[2] & SSE42_Flag) + sprintf(outbuf, "SSE42"); + else if (cpu_info[3] & SSE2_Flag) + sprintf(outbuf, "SSE2"); + else if (cpu_info[3] & SSE_Flag) + sprintf(outbuf, "SSE"); + else + *outbuf = '\0'; +#endif +} diff --git a/uint256.cpp b/uint256.cpp new file mode 100644 index 000000000..bb78891aa --- /dev/null +++ b/uint256.cpp @@ -0,0 +1,42 @@ +#include "uint256.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "miner.h" + +// compute the diff ratio between a found hash and the target +double hash_target_ratio(uint32_t* hash, uint32_t* target) +{ + uint256 h, t; + double dhash; + + if (!opt_showdiff) + return 0.0; + + memcpy(&t, (void*) target, 32); + memcpy(&h, (void*) hash, 32); + + dhash = h.getdouble(); + if (dhash > 0.) + return t.getdouble() / dhash; + else + return dhash; +} + +// store the share ratio in work struct +void work_set_target_ratio(struct work* work, uint32_t* hash) +{ + // only if the option is enabled (to reduce cpu usage) + if (opt_showdiff && work) { + work->shareratio = hash_target_ratio(hash, work->target); + work->sharediff = work->targetdiff * work->shareratio; + if (opt_debug) + applog(LOG_DEBUG, "share diff %.5f (%.1fx)", work->sharediff, work->shareratio); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/uint256.h b/uint256.h new file mode 100644 index 000000000..2a252c94f --- /dev/null +++ b/uint256.h @@ -0,0 +1,784 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_UINT256_H +#define BITCOIN_UINT256_H + +#include +#include +#include +#include +#include +#include + +typedef long long int64; +typedef unsigned long long uint64; + + +inline int Testuint256AdHoc(std::vector vArg); + + + +/** Base class without constructors for uint256 and uint160. + * This makes the compiler let you use it in a union. + */ +template +class base_uint +{ +protected: + enum { WIDTH=BITS/32 }; + uint32_t pn[WIDTH]; +public: + + bool operator!() const + { + for (int i = 0; i < WIDTH; i++) + if (pn[i] != 0) + return false; + return true; + } + + const base_uint operator~() const + { + base_uint ret; + for (int i = 0; i < WIDTH; i++) + ret.pn[i] = ~pn[i]; + return ret; + } + + const base_uint operator-() const + { + base_uint ret; + for (int i = 0; i < WIDTH; i++) + ret.pn[i] = ~pn[i]; + ret++; + return ret; + } + + double getdouble() const + { + double ret = 0.0; + double fact = 1.0; + for (int i = 0; i < WIDTH; i++) { + ret += fact * pn[i]; + fact *= 4294967296.0; + } + return ret; + } + + base_uint& operator=(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + base_uint& operator^=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] ^= b.pn[i]; + return *this; + } + + base_uint& operator&=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] &= b.pn[i]; + return *this; + } + + base_uint& operator|=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] |= b.pn[i]; + return *this; + } + + base_uint& operator^=(uint64 b) + { + pn[0] ^= (unsigned int)b; + pn[1] ^= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator|=(uint64 b) + { + pn[0] |= (unsigned int)b; + pn[1] |= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator<<=(unsigned int shift) + { + base_uint a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) + { + if (i+k+1 < WIDTH && shift != 0) + pn[i+k+1] |= (a.pn[i] >> (32-shift)); + if (i+k < WIDTH) + pn[i+k] |= (a.pn[i] << shift); + } + return *this; + } + + base_uint& operator>>=(unsigned int shift) + { + base_uint a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) + { + if (i-k-1 >= 0 && shift != 0) + pn[i-k-1] |= (a.pn[i] << (32-shift)); + if (i-k >= 0) + pn[i-k] |= (a.pn[i] >> shift); + } + return *this; + } + + base_uint& operator+=(const base_uint& b) + { + uint64 carry = 0; + for (int i = 0; i < WIDTH; i++) + { + uint64 n = carry + pn[i] + b.pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + return *this; + } + + base_uint& operator-=(const base_uint& b) + { + *this += -b; + return *this; + } + + base_uint& operator+=(uint64 b64) + { + base_uint b; + b = b64; + *this += b; + return *this; + } + + base_uint& operator-=(uint64 b64) + { + base_uint b; + b = b64; + *this += -b; + return *this; + } + + + base_uint& operator++() + { + // prefix operator + int i = 0; + while (++pn[i] == 0 && i < WIDTH-1) + i++; + return *this; + } + + const base_uint operator++(int) + { + // postfix operator + const base_uint ret = *this; + ++(*this); + return ret; + } + + base_uint& operator--() + { + // prefix operator + int i = 0; + while (--pn[i] == -1 && i < WIDTH-1) + i++; + return *this; + } + + const base_uint operator--(int) + { + // postfix operator + const base_uint ret = *this; + --(*this); + return ret; + } + + + friend inline bool operator<(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] < b.pn[i]) + return true; + else if (a.pn[i] > b.pn[i]) + return false; + } + return false; + } + + friend inline bool operator<=(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] < b.pn[i]) + return true; + else if (a.pn[i] > b.pn[i]) + return false; + } + return true; + } + + friend inline bool operator>(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] > b.pn[i]) + return true; + else if (a.pn[i] < b.pn[i]) + return false; + } + return false; + } + + friend inline bool operator>=(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] > b.pn[i]) + return true; + else if (a.pn[i] < b.pn[i]) + return false; + } + return true; + } + + friend inline bool operator==(const base_uint& a, const base_uint& b) + { + for (int i = 0; i < base_uint::WIDTH; i++) + if (a.pn[i] != b.pn[i]) + return false; + return true; + } + + friend inline bool operator==(const base_uint& a, uint64 b) + { + if (a.pn[0] != (unsigned int)b) + return false; + if (a.pn[1] != (unsigned int)(b >> 32)) + return false; + for (int i = 2; i < base_uint::WIDTH; i++) + if (a.pn[i] != 0) + return false; + return true; + } + + friend inline bool operator!=(const base_uint& a, const base_uint& b) + { + return (!(a == b)); + } + + friend inline bool operator!=(const base_uint& a, uint64 b) + { + return (!(a == b)); + } + + + + std::string GetHex() const + { + char psz[sizeof(pn)*2 + 1]; + for (unsigned int i = 0; i < sizeof(pn); i++) + sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); + return std::string(psz, psz + sizeof(pn)*2); + } + + void SetHex(const char* psz) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + + // skip leading spaces + while (isspace(*psz)) + psz++; + + // skip 0x + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + + // hex string to uint + static const unsigned char phexdigit[256] = { 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,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,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,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + const char* pbegin = psz; + while (phexdigit[(unsigned char)*psz] || *psz == '0') + psz++; + psz--; + unsigned char* p1 = (unsigned char*)pn; + unsigned char* pend = p1 + WIDTH * 4; + while (psz >= pbegin && p1 < pend) + { + *p1 = phexdigit[(unsigned char)*psz--]; + if (psz >= pbegin) + { + *p1 |= (phexdigit[(unsigned char)*psz--] << 4); + p1++; + } + } + } + + void SetHex(const std::string& str) + { + SetHex(str.c_str()); + } + + std::string ToString() const + { + return (GetHex()); + } + + unsigned char* begin() + { + return (unsigned char*)&pn[0]; + } + + unsigned char* end() + { + return (unsigned char*)&pn[WIDTH]; + } + + const unsigned char* begin() const + { + return (unsigned char*)&pn[0]; + } + + const unsigned char* end() const + { + return (unsigned char*)&pn[WIDTH]; + } + + unsigned int size() const + { + return sizeof(pn); + } + + uint64 Get64(int n=0) const + { + return pn[2*n] | (uint64)pn[2*n+1] << 32; + } + +// unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const + unsigned int GetSerializeSize(int nType, int nVersion) const + { + return sizeof(pn); + } + + template +// void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const + void Serialize(Stream& s, int nType, int nVersion) const + { + s.write((char*)pn, sizeof(pn)); + } + + template +// void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) + void Unserialize(Stream& s, int nType, int nVersion) + { + s.read((char*)pn, sizeof(pn)); + } + + + friend class uint160; + friend class uint256; + friend inline int Testuint256AdHoc(std::vector vArg); +}; + +typedef base_uint<160> base_uint160; +typedef base_uint<256> base_uint256; + + + +// +// uint160 and uint256 could be implemented as templates, but to keep +// compile errors and debugging cleaner, they're copy and pasted. +// + + + +////////////////////////////////////////////////////////////////////////////// +// +// uint160 +// + +/** 160-bit unsigned integer */ +class uint160 : public base_uint160 +{ +public: + typedef base_uint160 basetype; + + uint160() + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + } + + uint160(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + uint160& operator=(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + uint160(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + uint160& operator=(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + explicit uint160(const std::string& str) + { + SetHex(str); + } + + explicit uint160(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) + memcpy(pn, &vch[0], sizeof(pn)); + else + *this = 0; + } +}; + +inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } +inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } +inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } +inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } +inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } +inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } + +inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } +inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } +inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } +inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } +inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } + +inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } +inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } +inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } +inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } +inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } +inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } + +inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } +inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } +inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } +inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } +inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } +inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } + +inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } +inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } +inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } +inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } +inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } +inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// uint256 +// + +/** 256-bit unsigned integer */ +class uint256 : public base_uint256 +{ +public: + typedef base_uint256 basetype; + + uint256() + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + } + + uint256(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + uint256& operator=(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + uint256(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + uint256& operator=(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + explicit uint256(const std::string& str) + { + SetHex(str); + } + + explicit uint256(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) + memcpy(pn, &vch[0], sizeof(pn)); + else + *this = 0; + } +}; + +inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; } +inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; } +inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } +inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } +inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } +inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } + +inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } +inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } +inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } +inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } +inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } + +inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } +inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } +inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } +inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } +inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } +inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } +inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } +inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } +inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } +inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } +inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } + +inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } +inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } +inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } +inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } +inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } +inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } +inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } +inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } +inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } +inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } +inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } + +inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } +inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } +inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } +inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } +inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } +inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } +inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } +inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } +inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } +inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } +inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } + + + + + + + + + + +#ifdef TEST_UINT256 + +inline int Testuint256AdHoc(std::vector vArg) +{ + uint256 g(0); + + + printf("%s\n", g.ToString().c_str()); + g--; printf("g--\n"); + printf("%s\n", g.ToString().c_str()); + g--; printf("g--\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + + + + uint256 a(7); + printf("a=7\n"); + printf("%s\n", a.ToString().c_str()); + + uint256 b; + printf("b undefined\n"); + printf("%s\n", b.ToString().c_str()); + int c = 3; + + a = c; + a.pn[3] = 15; + printf("%s\n", a.ToString().c_str()); + uint256 k(c); + + a = 5; + a.pn[3] = 15; + printf("%s\n", a.ToString().c_str()); + b = 1; + b <<= 52; + + a |= b; + + a ^= 0x500; + + printf("a %s\n", a.ToString().c_str()); + + a = a | b | (uint256)0x1000; + + + printf("a %s\n", a.ToString().c_str()); + printf("b %s\n", b.ToString().c_str()); + + a = 0xfffffffe; + a.pn[4] = 9; + + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + + a--; + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + uint256 d = a--; + printf("%s\n", d.ToString().c_str()); + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + + d = a; + + printf("%s\n", d.ToString().c_str()); + for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n"); + + uint256 neg = d; + neg = ~neg; + printf("%s\n", neg.ToString().c_str()); + + + uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111"); + printf("\n"); + printf("%s\n", e.ToString().c_str()); + + + printf("\n"); + uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111"); + uint256 x2; + printf("%s\n", x1.ToString().c_str()); + for (int i = 0; i < 270; i += 4) + { + x2 = x1 << i; + printf("%s\n", x2.ToString().c_str()); + } + + printf("\n"); + printf("%s\n", x1.ToString().c_str()); + for (int i = 0; i < 270; i += 4) + { + x2 = x1; + x2 >>= i; + printf("%s\n", x2.ToString().c_str()); + } + + + for (int i = 0; i < 100; i++) + { + uint256 k = (~uint256(0) >> i); + printf("%s\n", k.ToString().c_str()); + } + + for (int i = 0; i < 100; i++) + { + uint256 k = (~uint256(0) << i); + printf("%s\n", k.ToString().c_str()); + } + + return (0); +} + +#endif + +#endif diff --git a/util.c b/util.c index 7251cb329..5ba320b53 100644 --- a/util.c +++ b/util.c @@ -1,5 +1,6 @@ /* * Copyright 2010 Jeff Garzik + * Copyright 2012 Luke Dashjr * Copyright 2012-2014 pooler * * This program is free software; you can redistribute it and/or modify it @@ -9,7 +10,7 @@ */ #define _GNU_SOURCE -#include "cpuminer-config.h" +#include #include #include @@ -18,23 +19,33 @@ #include #include #include +#include +#include #include #include #include #include +#include #if defined(WIN32) #include #include +#include "compat/winansi.h" #else -#include #include #include #include #endif -#include "compat.h" + +#ifndef _MSC_VER +/* dirname() linux/mingw, else in compat.h */ +#include +#endif + #include "miner.h" #include "elist.h" +extern pthread_mutex_t stats_lock; + struct data_buffer { void *buf; size_t len; @@ -77,7 +88,14 @@ void applog(int prio, const char *fmt, ...) va_list ap2; char *buf; int len; - + + /* custom colors to syslog prio */ + if (prio > LOG_DEBUG) { + switch (prio) { + case LOG_BLUE: prio = LOG_NOTICE; break; + } + } + va_copy(ap2, ap); len = vsnprintf(NULL, 0, fmt, ap2) + 1; va_end(ap2); @@ -89,36 +107,157 @@ void applog(int prio, const char *fmt, ...) if (0) {} #endif else { + const char* color = ""; char *f; int len; - time_t now; - struct tm tm, *tm_p; + struct tm tm; + time_t now = time(NULL); - time(&now); + localtime_r(&now, &tm); - pthread_mutex_lock(&applog_lock); - tm_p = localtime(&now); - memcpy(&tm, tm_p, sizeof(tm)); - pthread_mutex_unlock(&applog_lock); + switch (prio) { + case LOG_ERR: color = CL_RED; break; + case LOG_WARNING: color = CL_YLW; break; + case LOG_NOTICE: color = CL_WHT; break; + case LOG_INFO: color = ""; break; + case LOG_DEBUG: color = CL_GRY; break; + + case LOG_BLUE: + prio = LOG_NOTICE; + color = CL_CYN; + break; + } + if (!use_colors) + color = ""; - len = 40 + strlen(fmt) + 2; - f = alloca(len); - sprintf(f, "[%d-%02d-%02d %02d:%02d:%02d] %s\n", + len = 64 + (int) strlen(fmt) + 2; + f = (char*) malloc(len); + sprintf(f, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, - fmt); + color, + fmt, + use_colors ? CL_N : "" + ); pthread_mutex_lock(&applog_lock); - vfprintf(stderr, f, ap); /* atomic write to stderr */ - fflush(stderr); + vfprintf(stdout, f, ap); /* atomic write to stdout */ + fflush(stdout); + free(f); pthread_mutex_unlock(&applog_lock); } va_end(ap); } +/* Get default config.json path (will be system specific) */ +void get_defconfig_path(char *out, size_t bufsize, char *argv0) +{ + char *cmd = strdup(argv0); + char *dir = dirname(cmd); + const char *sep = strstr(dir, "\\") ? "\\" : "/"; + struct stat info = { 0 }; +#ifdef WIN32 + snprintf(out, bufsize, "%s\\cpuminer\\cpuminer-conf.json", getenv("APPDATA")); +#else + snprintf(out, bufsize, "%s\\.cpuminer\\cpuminer-conf.json", getenv("HOME")); +#endif + if (dir && stat(out, &info) != 0) { + snprintf(out, bufsize, "%s%scpuminer-conf.json", dir, sep); + } + if (stat(out, &info) != 0) { + out[0] = '\0'; + return; + } + out[bufsize - 1] = '\0'; + free(cmd); +} + + +void format_hashrate(double hashrate, char *output) +{ + char prefix = '\0'; + + if (hashrate < 10000) { + // nop + } + else if (hashrate < 1e7) { + prefix = 'k'; + hashrate *= 1e-3; + } + else if (hashrate < 1e10) { + prefix = 'M'; + hashrate *= 1e-6; + } + else if (hashrate < 1e13) { + prefix = 'G'; + hashrate *= 1e-9; + } + else { + prefix = 'T'; + hashrate *= 1e-12; + } + + sprintf( + output, + prefix ? "%.2f %cH/s" : "%.2f H/s%c", + hashrate, prefix + ); +} + +/* Modify the representation of integer numbers which would cause an overflow + * so that they are treated as floating-point numbers. + * This is a hack to overcome the limitations of some versions of Jansson. */ +static char *hack_json_numbers(const char *in) +{ + char *out; + int i, off, intoff; + bool in_str, in_int; + + out = (char*) calloc(2 * strlen(in) + 1, 1); + if (!out) + return NULL; + off = intoff = 0; + in_str = in_int = false; + for (i = 0; in[i]; i++) { + char c = in[i]; + if (c == '"') { + in_str = !in_str; + } else if (c == '\\') { + out[off++] = c; + if (!in[++i]) + break; + } else if (!in_str && !in_int && isdigit(c)) { + intoff = off; + in_int = true; + } else if (in_int && !isdigit(c)) { + if (c != '.' && c != 'e' && c != 'E' && c != '+' && c != '-') { + in_int = false; + if (off - intoff > 4) { + char *end; +#if JSON_INTEGER_IS_LONG_LONG + errno = 0; + strtoll(out + intoff, &end, 10); + if (!*end && errno == ERANGE) { +#else + long l; + errno = 0; + l = strtol(out + intoff, &end, 10); + if (!*end && (errno == ERANGE || l > INT_MAX)) { +#endif + out[off++] = '.'; + out[off++] = '0'; + } + } + } + } + out[off++] = in[i]; + } + return out; +} + static void databuf_free(struct data_buffer *db) { if (!db) @@ -132,7 +271,7 @@ static void databuf_free(struct data_buffer *db) static size_t all_data_cb(const void *ptr, size_t size, size_t nmemb, void *user_data) { - struct data_buffer *db = user_data; + struct data_buffer *db = (struct data_buffer *) user_data; size_t len = size * nmemb; size_t oldlen, newlen; void *newmem; @@ -147,8 +286,8 @@ static size_t all_data_cb(const void *ptr, size_t size, size_t nmemb, db->buf = newmem; db->len = newlen; - memcpy(db->buf + oldlen, ptr, len); - memcpy(db->buf + newlen, &zero, 1); /* null terminate */ + memcpy((uchar*) db->buf + oldlen, ptr, len); + memcpy((uchar*) db->buf + newlen, &zero, 1); /* null terminate */ return len; } @@ -156,14 +295,14 @@ static size_t all_data_cb(const void *ptr, size_t size, size_t nmemb, static size_t upload_data_cb(void *ptr, size_t size, size_t nmemb, void *user_data) { - struct upload_buffer *ub = user_data; - int len = size * nmemb; + struct upload_buffer *ub = (struct upload_buffer *) user_data; + size_t len = size * nmemb; if (len > ub->len - ub->pos) len = ub->len - ub->pos; if (len) { - memcpy(ptr, ub->buf + ub->pos, len); + memcpy(ptr, ((uchar*)ub->buf) + ub->pos, len); ub->pos += len; } @@ -173,17 +312,17 @@ static size_t upload_data_cb(void *ptr, size_t size, size_t nmemb, #if LIBCURL_VERSION_NUM >= 0x071200 static int seek_data_cb(void *user_data, curl_off_t offset, int origin) { - struct upload_buffer *ub = user_data; + struct upload_buffer *ub = (struct upload_buffer *) user_data; switch (origin) { case SEEK_SET: - ub->pos = offset; + ub->pos = (size_t) offset; break; case SEEK_CUR: - ub->pos += offset; + ub->pos += (size_t) offset; break; case SEEK_END: - ub->pos = ub->len + offset; + ub->pos = ub->len + (size_t) offset; break; default: return 1; /* CURL_SEEKFUNC_FAIL */ @@ -195,26 +334,26 @@ static int seek_data_cb(void *user_data, curl_off_t offset, int origin) static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data) { - struct header_info *hi = user_data; + struct header_info *hi = (struct header_info *) user_data; size_t remlen, slen, ptrlen = size * nmemb; char *rem, *val = NULL, *key = NULL; void *tmp; - val = calloc(1, ptrlen); - key = calloc(1, ptrlen); + val = (char*) calloc(1, ptrlen); + key = (char*) calloc(1, ptrlen); if (!key || !val) goto out; tmp = memchr(ptr, ':', ptrlen); if (!tmp || (tmp == ptr)) /* skip empty keys / blanks */ goto out; - slen = tmp - ptr; + slen = (char*)tmp - (char*)ptr; if ((slen + 1) == ptrlen) /* skip key w/ no value */ goto out; memcpy(key, ptr, slen); /* store & nul term key */ key[slen] = 0; - rem = ptr + slen + 1; /* trim value's leading whitespace */ + rem = (char*)ptr + slen + 1; /* trim value's leading whitespace */ remlen = ptrlen - slen - 1; while ((remlen > 0) && (isspace(*rem))) { remlen--; @@ -252,12 +391,13 @@ static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data) static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd, curlsocktype purpose) { - int keepalive = 1; +#ifdef __linux int tcp_keepcnt = 3; - int tcp_keepidle = 50; +#endif int tcp_keepintvl = 50; - + int tcp_keepidle = 50; #ifndef WIN32 + int keepalive = 1; if (unlikely(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)))) return 1; @@ -301,10 +441,11 @@ json_t *json_rpc_call(CURL *curl, const char *url, long http_rc; struct data_buffer all_data = {0}; struct upload_buffer upload_data; + char *json_buf; json_error_t err; struct curl_slist *headers = NULL; char len_hdr[64]; - char curl_err_str[CURL_ERROR_SIZE]; + char curl_err_str[CURL_ERROR_SIZE] = { 0 }; long timeout = (flags & JSON_RPC_LONGPOLL) ? opt_timeout : 30; struct header_info hi = {0}; @@ -315,8 +456,9 @@ json_t *json_rpc_call(CURL *curl, const char *url, curl_easy_setopt(curl, CURLOPT_URL, url); if (opt_cert) curl_easy_setopt(curl, CURLOPT_CAINFO, opt_cert); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_ENCODING, ""); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, all_data_cb); @@ -359,7 +501,7 @@ json_t *json_rpc_call(CURL *curl, const char *url, headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, len_hdr); headers = curl_slist_append(headers, "User-Agent: " USER_AGENT); - headers = curl_slist_append(headers, "X-Mining-Extensions: midstate"); + headers = curl_slist_append(headers, "X-Mining-Extensions: longpoll reject-reason"); //headers = curl_slist_append(headers, "Accept:"); /* disable Accept hdr*/ //headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/ @@ -373,6 +515,8 @@ json_t *json_rpc_call(CURL *curl, const char *url, if (!((flags & JSON_RPC_LONGPOLL) && rc == CURLE_OPERATION_TIMEDOUT) && !((flags & JSON_RPC_QUIET_404) && http_rc == 404)) applog(LOG_ERR, "HTTP request failed: %s", curl_err_str); + if (curl_err && (flags & JSON_RPC_QUIET_404) && http_rc == 404) + *curl_err = CURLE_OK; goto err_out; } @@ -385,7 +529,8 @@ json_t *json_rpc_call(CURL *curl, const char *url, } /* If X-Long-Polling was found, activate long polling */ - if (!have_longpoll && want_longpoll && hi.lp_path && !have_stratum) { + if (!have_longpoll && want_longpoll && hi.lp_path && !have_gbt && + allow_getwork && !have_stratum) { have_longpoll = true; tq_push(thr_info[longpoll_thr_id].q, hi.lp_path); hi.lp_path = NULL; @@ -396,7 +541,10 @@ json_t *json_rpc_call(CURL *curl, const char *url, goto err_out; } - val = JSON_LOADS(all_data.buf, &err); + json_buf = hack_json_numbers((char*) all_data.buf); + errno = 0; /* needed for Jansson < 2.1 */ + val = JSON_LOADS(json_buf, &err); + free(json_buf); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto err_out; @@ -408,20 +556,38 @@ json_t *json_rpc_call(CURL *curl, const char *url, free(s); } - /* JSON-RPC valid response returns a non-null 'result', - * and a null 'error'. */ + /* JSON-RPC valid response returns a 'result' and a null 'error'. */ res_val = json_object_get(val, "result"); err_val = json_object_get(val, "error"); - if ((err_val && !json_is_null(err_val) && !(flags & JSON_RPC_IGNOREERR))) { - char *s; - - if (err_val) - s = json_dumps(err_val, JSON_INDENT(3)); + if (!res_val || (err_val && !json_is_null(err_val) + && !(flags & JSON_RPC_IGNOREERR))) { + + char *s = NULL; + + if (err_val) { + s = json_dumps(err_val, 0); + json_t *msg = json_object_get(err_val, "message"); + json_t *err_code = json_object_get(err_val, "code"); + if (curl_err && json_integer_value(err_code)) + *curl_err = (int)json_integer_value(err_code); + + if (msg && json_is_string(msg)) { + free(s); + s = strdup(json_string_value(msg)); + if (have_longpoll && s && !strcmp(s, "method not getwork")) { + json_decref(err_val); + free(s); + goto err_out; + } + } + json_decref(err_val); + } else s = strdup("(unknown reason)"); - applog(LOG_ERR, "JSON-RPC call failed: %s", s); + if (!curl_err || opt_debug) + applog(LOG_ERR, "JSON-RPC call failed: %s", s); free(s); @@ -446,16 +612,64 @@ json_t *json_rpc_call(CURL *curl, const char *url, return NULL; } -char *bin2hex(const unsigned char *p, size_t len) +/* used to load a remote config */ +json_t* json_load_url(char* cfg_url, json_error_t *err) { - int i; - char *s = malloc((len * 2) + 1); - if (!s) + char err_str[CURL_ERROR_SIZE] = { 0 }; + struct data_buffer all_data = { 0 }; + int rc = 0; json_t *cfg = NULL; + CURL *curl = curl_easy_init(); + if (unlikely(!curl)) { + applog(LOG_ERR, "Remote config init failed!"); return NULL; + } + curl_easy_setopt(curl, CURLOPT_URL, cfg_url); + curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err_str); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, all_data_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &all_data); + if (opt_proxy) { + curl_easy_setopt(curl, CURLOPT_PROXY, opt_proxy); + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, opt_proxy_type); + } else if (getenv("http_proxy")) { + if (getenv("all_proxy")) + curl_easy_setopt(curl, CURLOPT_PROXY, getenv("all_proxy")); + else if (getenv("ALL_PROXY")) + curl_easy_setopt(curl, CURLOPT_PROXY, getenv("ALL_PROXY")); + else + curl_easy_setopt(curl, CURLOPT_PROXY, ""); + } + rc = curl_easy_perform(curl); + if (rc) { + applog(LOG_ERR, "Remote config read failed: %s", err_str); + goto err_out; + } + if (!all_data.buf || !all_data.len) { + applog(LOG_ERR, "Empty data received for config"); + goto err_out; + } + + cfg = JSON_LOADS((char*)all_data.buf, err); +err_out: + curl_easy_cleanup(curl); + return cfg; +} - for (i = 0; i < len; i++) +void bin2hex(char *s, const unsigned char *p, size_t len) +{ + for (size_t i = 0; i < len; i++) sprintf(s + (i * 2), "%02x", (unsigned int) p[i]); +} +char *abin2hex(const unsigned char *p, size_t len) +{ + char *s = (char*) malloc((len * 2) + 1); + if (!s) + return NULL; + bin2hex(s, p, len); return s; } @@ -483,7 +697,162 @@ bool hex2bin(unsigned char *p, const char *hexstr, size_t len) len--; } - return (len == 0 && *hexstr == 0) ? true : false; + return(!len) ? true : false; +/* return (len == 0 && *hexstr == 0) ? true : false; */ +} + +int varint_encode(unsigned char *p, uint64_t n) +{ + int i; + if (n < 0xfd) { + p[0] = (uchar) n; + return 1; + } + if (n <= 0xffff) { + p[0] = 0xfd; + p[1] = n & 0xff; + p[2] = (uchar) (n >> 8); + return 3; + } + if (n <= 0xffffffff) { + p[0] = 0xfe; + for (i = 1; i < 5; i++) { + p[i] = n & 0xff; + n >>= 8; + } + return 5; + } + p[0] = 0xff; + for (i = 1; i < 9; i++) { + p[i] = n & 0xff; + n >>= 8; + } + return 9; +} + +static const char b58digits[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +static bool b58dec(unsigned char *bin, size_t binsz, const char *b58) +{ + size_t i, j; + uint64_t t; + uint32_t c; + uint32_t *outi; + size_t outisz = (binsz + 3) / 4; + int rem = binsz % 4; + uint32_t remmask = 0xffffffff << (8 * rem); + size_t b58sz = strlen(b58); + bool rc = false; + + outi = (uint32_t *) calloc(outisz, sizeof(*outi)); + + for (i = 0; i < b58sz; ++i) { + for (c = 0; b58digits[c] != b58[i]; c++) + if (!b58digits[c]) + goto out; + for (j = outisz; j--; ) { + t = (uint64_t)outi[j] * 58 + c; + c = t >> 32; + outi[j] = t & 0xffffffff; + } + if (c || outi[0] & remmask) + goto out; + } + + j = 0; + switch (rem) { + case 3: + *(bin++) = (outi[0] >> 16) & 0xff; + case 2: + *(bin++) = (outi[0] >> 8) & 0xff; + case 1: + *(bin++) = outi[0] & 0xff; + ++j; + default: + break; + } + for (; j < outisz; ++j) { + be32enc((uint32_t *)bin, outi[j]); + bin += sizeof(uint32_t); + } + + rc = true; +out: + free(outi); + return rc; +} + +static int b58check(unsigned char *bin, size_t binsz, const char *b58) +{ + unsigned char buf[32]; + int i; + + sha256d(buf, bin, (int) (binsz - 4)); + if (memcmp(&bin[binsz - 4], buf, 4)) + return -1; + + /* Check number of zeros is correct AFTER verifying checksum + * (to avoid possibility of accessing the string beyond the end) */ + for (i = 0; bin[i] == '\0' && b58[i] == '1'; ++i); + if (bin[i] == '\0' || b58[i] == '1') + return -3; + + return bin[0]; +} + +bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen) +{ + const char *hexstr; + json_t *tmp; + + tmp = json_object_get(obj, key); + if (unlikely(!tmp)) { + applog(LOG_ERR, "JSON key '%s' not found", key); + return false; + } + hexstr = json_string_value(tmp); + if (unlikely(!hexstr)) { + applog(LOG_ERR, "JSON key '%s' is not a string", key); + return false; + } + if (!hex2bin((uchar*) buf, hexstr, buflen)) + return false; + + return true; +} + +size_t address_to_script(unsigned char *out, size_t outsz, const char *addr) +{ + unsigned char addrbin[25]; + int addrver; + size_t rv; + + if (!b58dec(addrbin, sizeof(addrbin), addr)) + return 0; + addrver = b58check(addrbin, sizeof(addrbin), addr); + if (addrver < 0) + return 0; + switch (addrver) { + case 5: /* Bitcoin script hash */ + case 196: /* Testnet script hash */ + if (outsz < (rv = 23)) + return rv; + out[ 0] = 0xa9; /* OP_HASH160 */ + out[ 1] = 0x14; /* push 20 bytes */ + memcpy(&out[2], &addrbin[1], 20); + out[22] = 0x87; /* OP_EQUAL */ + return rv; + default: + if (outsz < (rv = 25)) + return rv; + out[ 0] = 0x76; /* OP_DUP */ + out[ 1] = 0xa9; /* OP_HASH160 */ + out[ 2] = 0x14; /* push 20 bytes */ + memcpy(&out[3], &addrbin[1], 20); + out[23] = 0x88; /* OP_EQUALVERIFY */ + out[24] = 0xac; /* OP_CHECKSIG */ + return rv; + } } /* Subtract the `struct timeval' values X and Y, @@ -531,23 +900,20 @@ bool fulltest(const uint32_t *hash, const uint32_t *target) if (opt_debug) { uint32_t hash_be[8], target_be[8]; - char *hash_str, *target_str; + char hash_str[65], target_str[65]; for (i = 0; i < 8; i++) { be32enc(hash_be + i, hash[7 - i]); be32enc(target_be + i, target[7 - i]); } - hash_str = bin2hex((unsigned char *)hash_be, 32); - target_str = bin2hex((unsigned char *)target_be, 32); + bin2hex(hash_str, (unsigned char *)hash_be, 32); + bin2hex(target_str, (unsigned char *)target_be, 32); applog(LOG_DEBUG, "DEBUG: %s\nHash: %s\nTarget: %s", rc ? "hash <= target" : "hash > target (false positive)", hash_str, target_str); - - free(hash_str); - free(target_str); } return rc; @@ -560,7 +926,7 @@ void diff_to_target(uint32_t *target, double diff) for (k = 6; k > 0 && diff > 1.0; k--) diff /= 4294967296.0; - m = 4294901760.0 / diff; + m = (uint64_t)(4294901760.0 / diff); if (m == 0 && k == 6) memset(target, 0xff, 32); else { @@ -570,6 +936,33 @@ void diff_to_target(uint32_t *target, double diff) } } +// Only used by stratum pools +void work_set_target(struct work* work, double diff) +{ + diff_to_target(work->target, diff); + work->targetdiff = diff; +} + +// Only used by longpoll pools +double target_to_diff(uint32_t* target) +{ + uchar* tgt = (uchar*) target; + uint64_t m = + (uint64_t)tgt[29] << 56 | + (uint64_t)tgt[28] << 48 | + (uint64_t)tgt[27] << 40 | + (uint64_t)tgt[26] << 32 | + (uint64_t)tgt[25] << 24 | + (uint64_t)tgt[24] << 16 | + (uint64_t)tgt[23] << 8 | + (uint64_t)tgt[22] << 0; + + if (!m) + return 0.; + else + return (double)0x0000ffff00000000/m; +} + #ifdef WIN32 #define socket_blocks() (WSAGetLastError() == WSAEWOULDBLOCK) #else @@ -578,19 +971,20 @@ void diff_to_target(uint32_t *target, double diff) static bool send_line(curl_socket_t sock, char *s) { - ssize_t len, sent = 0; - - len = strlen(s); + size_t sent = 0; + int len; + + len = (int) strlen(s); s[len++] = '\n'; while (len > 0) { struct timeval timeout = {0, 0}; - ssize_t n; + int n; fd_set wd; FD_ZERO(&wd); FD_SET(sock, &wd); - if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1) + if (select((int) (sock + 1), NULL, &wd, NULL, &timeout) < 1) return false; n = send(sock, s + sent, len, 0); if (n < 0) { @@ -628,7 +1022,7 @@ static bool socket_full(curl_socket_t sock, int timeout) FD_SET(sock, &rd); tv.tv_sec = timeout; tv.tv_usec = 0; - if (select(sock + 1, &rd, NULL, NULL, &tv) > 0) + if (select((int)(sock + 1), &rd, NULL, NULL, &tv) > 0) return true; return false; } @@ -643,13 +1037,13 @@ bool stratum_socket_full(struct stratum_ctx *sctx, int timeout) static void stratum_buffer_append(struct stratum_ctx *sctx, const char *s) { - size_t old, new; + size_t old, n; old = strlen(sctx->sockbuf); - new = old + strlen(s) + 1; - if (new >= sctx->sockbuf_size) { - sctx->sockbuf_size = new + (RBUFSIZE - (new % RBUFSIZE)); - sctx->sockbuf = realloc(sctx->sockbuf, sctx->sockbuf_size); + n = old + strlen(s) + 1; + if (n >= sctx->sockbuf_size) { + sctx->sockbuf_size = n + (RBUFSIZE - (n % RBUFSIZE)); + sctx->sockbuf = (char*) realloc(sctx->sockbuf, sctx->sockbuf_size); } strcpy(sctx->sockbuf + old, s); } @@ -693,14 +1087,14 @@ char *stratum_recv_line(struct stratum_ctx *sctx) } } - buflen = strlen(sctx->sockbuf); + buflen = (ssize_t) strlen(sctx->sockbuf); tok = strtok(sctx->sockbuf, "\n"); if (!tok) { applog(LOG_ERR, "stratum_recv_line failed to parse a newline-terminated string"); goto out; } sret = strdup(tok); - len = strlen(sret); + len = (ssize_t) strlen(sret); if (buflen > len + 1) memmove(sctx->sockbuf, sctx->sockbuf + len + 1, buflen - len + 1); @@ -717,7 +1111,7 @@ char *stratum_recv_line(struct stratum_ctx *sctx) static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose, struct curl_sockaddr *addr) { - curl_socket_t *sock = clientp; + curl_socket_t *sock = (curl_socket_t*) clientp; *sock = socket(addr->family, addr->socktype, addr->protocol); return *sock; } @@ -739,7 +1133,7 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url) } curl = sctx->curl; if (!sctx->sockbuf) { - sctx->sockbuf = calloc(RBUFSIZE, 1); + sctx->sockbuf = (char*) calloc(RBUFSIZE, 1); sctx->sockbuf_size = RBUFSIZE; } sctx->sockbuf[0] = '\0'; @@ -750,7 +1144,7 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url) sctx->url = strdup(url); } free(sctx->curl_url); - sctx->curl_url = malloc(strlen(url)); + sctx->curl_url = (char*) malloc(strlen(url)); sprintf(sctx->curl_url, "http%s", strstr(url, "://")); if (opt_protocol) @@ -810,7 +1204,7 @@ static const char *get_stratum_session_id(json_t *val) arr_val = json_array_get(val, 0); if (!arr_val || !json_is_array(arr_val)) return NULL; - n = json_array_size(arr_val); + n = (int) json_array_size(arr_val); for (i = 0; i < n; i++) { const char *notify; json_t *arr = json_array_get(arr_val, i); @@ -826,18 +1220,62 @@ static const char *get_stratum_session_id(json_t *val) return NULL; } +static bool stratum_parse_extranonce(struct stratum_ctx *sctx, json_t *params, int pndx) +{ + const char* xnonce1; + int xn2_size; + + xnonce1 = json_string_value(json_array_get(params, pndx)); + if (!xnonce1) { + applog(LOG_ERR, "Failed to get extranonce1"); + goto out; + } + xn2_size = (int) json_integer_value(json_array_get(params, pndx+1)); + if (!xn2_size) { + applog(LOG_ERR, "Failed to get extranonce2_size"); + goto out; + } + if (xn2_size < 2 || xn2_size > 16) { + applog(LOG_INFO, "Failed to get valid n2size in parse_extranonce"); + goto out; + } + + pthread_mutex_lock(&sctx->work_lock); + if (sctx->xnonce1) + free(sctx->xnonce1); + sctx->xnonce1_size = strlen(xnonce1) / 2; + sctx->xnonce1 = (uchar*) calloc(1, sctx->xnonce1_size); + if (unlikely(!sctx->xnonce1)) { + applog(LOG_ERR, "Failed to alloc xnonce1"); + pthread_mutex_unlock(&sctx->work_lock); + goto out; + } + hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size); + sctx->xnonce2_size = xn2_size; + pthread_mutex_unlock(&sctx->work_lock); + + if (pndx == 0 && opt_debug) /* pool dynamic change */ + applog(LOG_DEBUG, "Stratum set nonce %s with extranonce2 size=%d", + xnonce1, xn2_size); + + return true; +out: + return false; +} + bool stratum_subscribe(struct stratum_ctx *sctx) { - if(jsonrpc_2) return true; char *s, *sret = NULL; - const char *sid, *xnonce1; - int xn2_size; + const char *sid; json_t *val = NULL, *res_val, *err_val; json_error_t err; bool ret = false, retry = false; + if (jsonrpc_2) + return true; + start: - s = malloc(128 + (sctx->session_id ? strlen(sctx->session_id) : 0)); + s = (char*) malloc(128 + (sctx->session_id ? strlen(sctx->session_id) : 0)); if (retry) sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": []}"); else if (sctx->session_id) @@ -883,32 +1321,20 @@ bool stratum_subscribe(struct stratum_ctx *sctx) } sid = get_stratum_session_id(res_val); - if (opt_debug && !sid) - applog(LOG_DEBUG, "Failed to get Stratum session id"); - xnonce1 = json_string_value(json_array_get(res_val, 1)); - if (!xnonce1) { - applog(LOG_ERR, "Failed to get extranonce1"); - goto out; - } - xn2_size = json_integer_value(json_array_get(res_val, 2)); - if (!xn2_size) { - applog(LOG_ERR, "Failed to get extranonce2_size"); - goto out; - } + if (opt_debug && sid) + applog(LOG_DEBUG, "Stratum session id: %s", sid); pthread_mutex_lock(&sctx->work_lock); - free(sctx->session_id); - free(sctx->xnonce1); + if (sctx->session_id) + free(sctx->session_id); sctx->session_id = sid ? strdup(sid) : NULL; - sctx->xnonce1_size = strlen(xnonce1) / 2; - sctx->xnonce1 = malloc(sctx->xnonce1_size); - hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size); - sctx->xnonce2_size = xn2_size; sctx->next_diff = 1.0; pthread_mutex_unlock(&sctx->work_lock); - if (opt_debug && sid) - applog(LOG_DEBUG, "Stratum session id: %s", sctx->session_id); + // sid is param 1, extranonce params are 2 and 3 + if (!stratum_parse_extranonce(sctx, res_val, 1)) { + goto out; + } ret = true; @@ -927,21 +1353,25 @@ bool stratum_subscribe(struct stratum_ctx *sctx) return ret; } +extern bool opt_extranonce; + bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass) { json_t *val = NULL, *res_val, *err_val; char *s, *sret; json_error_t err; bool ret = false; + int req_id = 0; - if(jsonrpc_2) { - s = malloc(300 + strlen(user) + strlen(pass)); - sprintf(s, "{\"method\": \"login\", \"params\": {\"login\": \"%s\", \"pass\": \"%s\", \"agent\": \"cpuminer-multi/0.1\"}, \"id\": 1}", - user, pass); + if (jsonrpc_2) { + s = (char*) malloc(300 + strlen(user) + strlen(pass)); + sprintf(s, "{\"method\": \"login\", \"params\": {" + "\"login\": \"%s\", \"pass\": \"%s\", \"agent\": \"%s\"}, \"id\": 1}", + user, pass, USER_AGENT); } else { - s = malloc(80 + strlen(user) + strlen(pass)); - sprintf(s, "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", - user, pass); + s = (char*) malloc(80 + strlen(user) + strlen(pass)); + sprintf(s, "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", + user, pass); } if (!stratum_send_line(sctx, s)) @@ -965,23 +1395,55 @@ bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *p res_val = json_object_get(val, "result"); err_val = json_object_get(val, "error"); + req_id = (int) json_integer_value(json_object_get(val, "id")); - if (!res_val || json_is_false(res_val) || - (err_val && !json_is_null(err_val))) { + if (req_id == 2 + && (!res_val || json_is_false(res_val) || (err_val && !json_is_null(err_val)))) { applog(LOG_ERR, "Stratum authentication failed"); goto out; } - if(jsonrpc_2) { - rpc2_login_decode(val); - json_t *job_val = json_object_get(res_val, "job"); - pthread_mutex_lock(&sctx->work_lock); - if(job_val) rpc2_job_decode(job_val, &sctx->work); - pthread_mutex_unlock(&sctx->work_lock); - } + if (jsonrpc_2) { + rpc2_login_decode(val); + json_t *job_val = json_object_get(res_val, "job"); + pthread_mutex_lock(&sctx->work_lock); + if(job_val) rpc2_job_decode(job_val, &sctx->work); + pthread_mutex_unlock(&sctx->work_lock); + } ret = true; + if (!opt_extranonce) + goto out; + + // subscribe to extranonce (optional) + sprintf(s, "{\"id\": 3, \"method\": \"mining.extranonce.subscribe\", \"params\": []}"); + + if (!stratum_send_line(sctx, s)) + goto out; + + if (!socket_full(sctx->sock, 3)) { + if (opt_debug) + applog(LOG_DEBUG, "stratum extranonce subscribe timed out"); + goto out; + } + + sret = stratum_recv_line(sctx); + if (sret) { + json_t *extra = JSON_LOADS(sret, &err); + if (!extra) { + applog(LOG_WARNING, "JSON decode failed(%d): %s", err.line, err.text); + } else { + if (json_integer_value(json_object_get(extra, "id")) != 3) { + // we receive a standard method if extranonce is ignored + if (!stratum_handle_method(sctx, sret)) + applog(LOG_WARNING, "Stratum answer id is not correct!"); + } + json_decref(extra); + } + free(sret); + } + out: free(s); if (val) @@ -990,36 +1452,275 @@ bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *p return ret; } -static bool stratum_2_job(struct stratum_ctx *sctx, json_t *params) +// -------------------- RPC 2.0 (XMR/AEON) ------------------------- + +extern pthread_mutex_t rpc2_login_lock; +extern pthread_mutex_t rpc2_job_lock; + +bool rpc2_login_decode(const json_t *val) +{ + const char *id; + const char *s; + + json_t *res = json_object_get(val, "result"); + if(!res) { + applog(LOG_ERR, "JSON invalid result"); + goto err_out; + } + + json_t *tmp; + tmp = json_object_get(res, "id"); + if(!tmp) { + applog(LOG_ERR, "JSON inval id"); + goto err_out; + } + id = json_string_value(tmp); + if(!id) { + applog(LOG_ERR, "JSON id is not a string"); + goto err_out; + } + + memcpy(&rpc2_id, id, 64); + + if(opt_debug) + applog(LOG_DEBUG, "Auth id: %s", id); + + tmp = json_object_get(res, "status"); + if(!tmp) { + applog(LOG_ERR, "JSON inval status"); + goto err_out; + } + s = json_string_value(tmp); + if(!s) { + applog(LOG_ERR, "JSON status is not a string"); + goto err_out; + } + if(strcmp(s, "OK")) { + applog(LOG_ERR, "JSON returned status \"%s\"", s); + return false; + } + + return true; + +err_out: + applog(LOG_WARNING,"%s: fail", __func__); + return false; +} + +json_t* json_rpc2_call_recur(CURL *curl, const char *url, const char *userpass, + json_t *rpc_req, int *curl_err, int flags, int recur) +{ + if(recur >= 5) { + if(opt_debug) + applog(LOG_DEBUG, "Failed to call rpc command after %i tries", recur); + return NULL; + } + if(!strcmp(rpc2_id, "")) { + if(opt_debug) + applog(LOG_DEBUG, "Tried to call rpc2 command before authentication"); + return NULL; + } + json_t *params = json_object_get(rpc_req, "params"); + if (params) { + json_t *auth_id = json_object_get(params, "id"); + if (auth_id) { + json_string_set(auth_id, rpc2_id); + } + } + json_t *res = json_rpc_call(curl, url, userpass, json_dumps(rpc_req, 0), + curl_err, flags | JSON_RPC_IGNOREERR); + if(!res) goto end; + json_t *error = json_object_get(res, "error"); + if(!error) goto end; + json_t *message; + if(json_is_string(error)) + message = error; + else + message = json_object_get(error, "message"); + if(!message || !json_is_string(message)) goto end; + const char *mes = json_string_value(message); + if(!strcmp(mes, "Unauthenticated")) { + pthread_mutex_lock(&rpc2_login_lock); + rpc2_login(curl); + sleep(1); + pthread_mutex_unlock(&rpc2_login_lock); + return json_rpc2_call_recur(curl, url, userpass, rpc_req, + curl_err, flags, recur + 1); + } else if(!strcmp(mes, "Low difficulty share") || !strcmp(mes, "Block expired") || !strcmp(mes, "Invalid job id") || !strcmp(mes, "Duplicate share")) { + json_t *result = json_object_get(res, "result"); + if(!result) { + goto end; + } + json_object_set(result, "reject-reason", json_string(mes)); + } else { + applog(LOG_ERR, "json_rpc2.0 error: %s", mes); + return NULL; + } + end: + return res; +} + +json_t *json_rpc2_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req, int *curl_err, int flags) { - bool ret = false; - pthread_mutex_lock(&sctx->work_lock); - ret = rpc2_job_decode(params, &sctx->work); - pthread_mutex_unlock(&sctx->work_lock); - return ret; + json_t* req_json = JSON_LOADS(rpc_req, NULL); + json_t* res = json_rpc2_call_recur(curl, url, userpass, req_json, curl_err, flags, 0); + json_decref(req_json); + return res; +} + +bool rpc2_job_decode(const json_t *job, struct work *work) +{ + if (!jsonrpc_2) { + applog(LOG_ERR, "Tried to decode job without JSON-RPC 2.0"); + return false; + } + json_t *tmp; + tmp = json_object_get(job, "job_id"); + if (!tmp) { + applog(LOG_ERR, "JSON invalid job id"); + goto err_out; + } + const char *job_id = json_string_value(tmp); + tmp = json_object_get(job, "blob"); + if (!tmp) { + applog(LOG_ERR, "JSON invalid blob"); + goto err_out; + } + const char *hexblob = json_string_value(tmp); + size_t blobLen = strlen(hexblob); + if (blobLen % 2 != 0 || ((blobLen / 2) < 40 && blobLen != 0) || (blobLen / 2) > 128) { + applog(LOG_ERR, "JSON invalid blob length"); + goto err_out; + } + if (blobLen != 0) { + uint32_t target = 0; + pthread_mutex_lock(&rpc2_job_lock); + uchar *blob = (uchar*) malloc(blobLen / 2); + if (!hex2bin(blob, hexblob, blobLen / 2)) { + applog(LOG_ERR, "JSON invalid blob"); + pthread_mutex_unlock(&rpc2_job_lock); + goto err_out; + } + rpc2_bloblen = blobLen / 2; + if (rpc2_blob) free(rpc2_blob); + rpc2_blob = (char*) malloc(rpc2_bloblen); + if (!rpc2_blob) { + applog(LOG_ERR, "RPC2 OOM!"); + goto err_out; + } + memcpy(rpc2_blob, blob, blobLen / 2); + free(blob); + + jobj_binary(job, "target", &target, 4); + if(rpc2_target != target) { + double hashrate = 0.0; + pthread_mutex_lock(&stats_lock); + for (int i = 0; i < opt_n_threads; i++) + hashrate += thr_hashrates[i]; + pthread_mutex_unlock(&stats_lock); + double difficulty = (((double) 0xffffffff) / target); + if (!opt_quiet) { + // xmr pool diff can change a lot... + applog(LOG_WARNING, "Stratum difficulty set to %g", difficulty); + } + stratum_diff = difficulty; + rpc2_target = target; + } + + if (rpc2_job_id) free(rpc2_job_id); + rpc2_job_id = strdup(job_id); + pthread_mutex_unlock(&rpc2_job_lock); + } + if(work) { + if (!rpc2_blob) { + applog(LOG_WARNING, "Work requested before it was received"); + goto err_out; + } + memcpy(work->data, rpc2_blob, rpc2_bloblen); + memset(work->target, 0xff, sizeof(work->target)); + work->target[7] = rpc2_target; + if (work->job_id) free(work->job_id); + work->job_id = strdup(rpc2_job_id); + } + return true; + +err_out: + applog(LOG_WARNING, "%s", __func__); + return false; +} + +/** + * Extract bloc height L H... here len=3, height=0x1333e8 + * "...0000000000ffffffff2703e83313062f503253482f043d61105408" + */ +static uint32_t getblocheight(struct stratum_ctx *sctx) +{ + uint32_t height = 0; + uint8_t hlen = 0, *p, *m; + + // find 0xffff tag + p = (uint8_t*) sctx->job.coinbase + 32; + m = p + 128; + while (*p != 0xff && p < m) p++; + while (*p == 0xff && p < m) p++; + if (*(p-1) == 0xff && *(p-2) == 0xff) { + p++; hlen = *p; + p++; height = le16dec(p); + p += 2; + switch (hlen) { + case 4: + height += 0x10000UL * le16dec(p); + break; + case 3: + height += 0x10000UL * (*p); + break; + } + } + return height; } static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) { + char algo[64] = { 0 }; const char *job_id, *prevhash, *coinb1, *coinb2, *version, *nbits, *ntime; + const char *extradata = NULL; size_t coinb1_size, coinb2_size; bool clean, ret = false; - int merkle_count, i; + int merkle_count, i, p=0; + bool has_claim, has_roots; json_t *merkle_arr; - unsigned char **merkle; - - job_id = json_string_value(json_array_get(params, 0)); - prevhash = json_string_value(json_array_get(params, 1)); - coinb1 = json_string_value(json_array_get(params, 2)); - coinb2 = json_string_value(json_array_get(params, 3)); - merkle_arr = json_array_get(params, 4); + uchar **merkle; + + get_currentalgo(algo, sizeof(algo)); + has_claim = strcmp(algo, "lbry") == 0 && json_array_size(params) == 10; + has_roots = strcmp(algo, "phi2") == 0 && json_array_size(params) == 10; + + job_id = json_string_value(json_array_get(params, p++)); + prevhash = json_string_value(json_array_get(params, p++)); + if (has_claim) { + extradata = json_string_value(json_array_get(params, p++)); + if (!extradata || strlen(extradata) != 64) { + applog(LOG_ERR, "Stratum notify: invalid claim parameter"); + goto out; + } + } + else if (has_roots) { + extradata = json_string_value(json_array_get(params, p++)); + if (!extradata || strlen(extradata) != 128) { + applog(LOG_ERR, "Stratum notify: invalid UTXO root parameter"); + goto out; + } + } + coinb1 = json_string_value(json_array_get(params, p++)); + coinb2 = json_string_value(json_array_get(params, p++)); + merkle_arr = json_array_get(params, p++); if (!merkle_arr || !json_is_array(merkle_arr)) goto out; - merkle_count = json_array_size(merkle_arr); - version = json_string_value(json_array_get(params, 5)); - nbits = json_string_value(json_array_get(params, 6)); - ntime = json_string_value(json_array_get(params, 7)); - clean = json_is_true(json_array_get(params, 8)); + merkle_count = (int) json_array_size(merkle_arr); + version = json_string_value(json_array_get(params, p++)); + nbits = json_string_value(json_array_get(params, p++)); + ntime = json_string_value(json_array_get(params, p++)); + clean = json_is_true(json_array_get(params, p)); if (!job_id || !prevhash || !coinb1 || !coinb2 || !version || !nbits || !ntime || strlen(prevhash) != 64 || strlen(version) != 8 || @@ -1027,7 +1728,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) applog(LOG_ERR, "Stratum notify: invalid parameters"); goto out; } - merkle = malloc(merkle_count * sizeof(char *)); + merkle = (uchar**) malloc(merkle_count * sizeof(char *)); for (i = 0; i < merkle_count; i++) { const char *s = json_string_value(json_array_get(merkle_arr, i)); if (!s || strlen(s) != 64) { @@ -1037,7 +1738,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) applog(LOG_ERR, "Stratum notify: invalid Merkle branch"); goto out; } - merkle[i] = malloc(32); + merkle[i] = (uchar*) malloc(32); hex2bin(merkle[i], s, 32); } @@ -1047,7 +1748,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) coinb2_size = strlen(coinb2) / 2; sctx->job.coinbase_size = coinb1_size + sctx->xnonce1_size + sctx->xnonce2_size + coinb2_size; - sctx->job.coinbase = realloc(sctx->job.coinbase, sctx->job.coinbase_size); + sctx->job.coinbase = (uchar*) realloc(sctx->job.coinbase, sctx->job.coinbase_size); sctx->job.xnonce2 = sctx->job.coinbase + coinb1_size + sctx->xnonce1_size; hex2bin(sctx->job.coinbase, coinb1, coinb1_size); memcpy(sctx->job.coinbase + coinb1_size, sctx->xnonce1, sctx->xnonce1_size); @@ -1059,6 +1760,11 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) sctx->job.job_id = strdup(job_id); hex2bin(sctx->job.prevhash, prevhash, 32); + if (has_claim) hex2bin(sctx->job.extra, extradata, 32); + if (has_roots) hex2bin(sctx->job.extra, extradata, 64); + + sctx->bloc_height = getblocheight(sctx); + for (i = 0; i < sctx->job.merkle_count; i++) free(sctx->job.merkle[i]); free(sctx->job.merkle); @@ -1092,9 +1798,6 @@ static bool stratum_set_difficulty(struct stratum_ctx *sctx, json_t *params) sctx->next_diff = diff; pthread_mutex_unlock(&sctx->work_lock); - if (opt_debug) - applog(LOG_DEBUG, "Stratum difficulty set to %g", diff); - return true; } @@ -1110,11 +1813,11 @@ static bool stratum_reconnect(struct stratum_ctx *sctx, json_t *params) if (json_is_string(port_val)) port = atoi(json_string_value(port_val)); else - port = json_integer_value(port_val); + port = (int) json_integer_value(port_val); if (!host || !port) return false; - url = malloc(32 + strlen(host)); + url = (char*) malloc(32 + strlen(host)); sprintf(url, "stratum+tcp://%s:%d", host, port); if (!opt_redirect) { @@ -1132,6 +1835,193 @@ static bool stratum_reconnect(struct stratum_ctx *sctx, json_t *params) return true; } +static bool json_object_set_error(json_t *result, int code, const char *msg) +{ + json_t *val = json_object(); + json_object_set_new(val, "code", json_integer(code)); + json_object_set_new(val, "message", json_string(msg)); + return json_object_set_new(result, "error", val) != -1; +} + +/* allow to report algo perf to the pool for algo stats */ +static bool stratum_benchdata(json_t *result, json_t *params, int thr_id) +{ + char algo[64] = { 0 }; + char cpuname[80] = { 0 }; + char vendorid[32] = { 0 }; + char compiler[32] = { 0 }; + char arch[16] = { 0 }; + char os[8]; + char *p; + double cpufreq = 0; + json_t *val; + + if (!opt_stratum_stats) return false; + + get_currentalgo(algo, sizeof(algo)); + +#if defined(WIN32) && (defined(_M_X64) || defined(__x86_64__)) + strcpy(os, "win64"); +#else + strcpy(os, is_windows() ? "win32" : "linux"); +#endif + +#ifdef _MSC_VER + sprintf(compiler, "MSVC %d\n", msver()); +#elif defined(__clang__) + sprintf(compiler, "clang %s\n", __clang_version__); +#elif defined(__GNUC__) + sprintf(compiler, "GCC %d.%d.%d\n", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +#endif + +#ifdef __AVX2__ + strcat(compiler, " AVX2"); +#elif defined(__AVX__) + strcat(compiler, " AVX"); +#elif defined(__FMA4__) + strcat(compiler, " FMA4"); +#elif defined(__FMA3__) + strcat(compiler, " FMA3"); +#elif defined(__SSE4_2__) + strcat(compiler, " SSE4.2"); +#elif defined(__SSE4_1__) + strcat(compiler, " SSE4"); +#elif defined(__SSE3__) + strcat(compiler, " SSE3"); +#elif defined(__SSE2__) + strcat(compiler, " SSE2"); +#elif defined(__SSE__) + strcat(compiler, " SSE"); +#endif + + cpu_bestfeature(arch, 16); + if (has_aes_ni()) strcat(arch, " NI"); + + cpu_getmodelid(vendorid, 32); + cpu_getname(cpuname, 80); + p = strstr(cpuname, " @ "); + if (p) { + char freq[32] = { 0 }; + *p = '\0'; p += 3; + snprintf(freq, 32, "%s", p); + cpufreq = atof(freq); + p = strstr(freq, "GHz"); if (p) cpufreq *= 1000; + applog(LOG_NOTICE, "sharing CPU stats with freq %s", freq); + } + + compiler[31] = '\0'; + + val = json_object(); + json_object_set_new(val, "algo", json_string(algo)); + json_object_set_new(val, "type", json_string("cpu")); + json_object_set_new(val, "device", json_string(cpuname)); + json_object_set_new(val, "vendorid", json_string(vendorid)); + json_object_set_new(val, "arch", json_string(arch)); + json_object_set_new(val, "freq", json_integer((uint64_t)cpufreq)); + json_object_set_new(val, "memf", json_integer(0)); + json_object_set_new(val, "power", json_integer(0)); + json_object_set_new(val, "khashes", json_real((double)global_hashrate / 1000.0)); + json_object_set_new(val, "intensity", json_real(opt_priority)); + json_object_set_new(val, "throughput", json_integer(opt_n_threads)); + json_object_set_new(val, "client", json_string(PACKAGE_NAME "/" PACKAGE_VERSION)); + json_object_set_new(val, "os", json_string(os)); + json_object_set_new(val, "driver", json_string(compiler)); + + json_object_set_new(result, "result", val); + + return true; +} + +static bool stratum_get_stats(struct stratum_ctx *sctx, json_t *id, json_t *params) +{ + char *s; + json_t *val; + bool ret; + + if (!id || json_is_null(id)) + return false; + + val = json_object(); + json_object_set(val, "id", id); + + ret = stratum_benchdata(val, params, 0); + + if (!ret) { + json_object_set_error(val, 1, "disabled"); //EPERM + } else { + json_object_set_new(val, "error", json_null()); + } + + s = json_dumps(val, 0); + ret = stratum_send_line(sctx, s); + json_decref(val); + free(s); + + return ret; +} + +static bool stratum_unknown_method(struct stratum_ctx *sctx, json_t *id) +{ + char *s; + json_t *val; + bool ret = false; + + if (!id || json_is_null(id)) + return ret; + + val = json_object(); + json_object_set(val, "id", id); + json_object_set_new(val, "result", json_false()); + json_object_set_error(val, 38, "unknown method"); // ENOSYS + + s = json_dumps(val, 0); + ret = stratum_send_line(sctx, s); + json_decref(val); + free(s); + + return ret; +} + +static bool stratum_pong(struct stratum_ctx *sctx, json_t *id) +{ + char buf[64]; + bool ret = false; + + if (!id || json_is_null(id)) + return ret; + + sprintf(buf, "{\"id\":%d,\"result\":\"pong\",\"error\":null}", + (int) json_integer_value(id)); + ret = stratum_send_line(sctx, buf); + + return ret; +} + +static bool stratum_get_algo(struct stratum_ctx *sctx, json_t *id, json_t *params) +{ + char algo[64] = { 0 }; + char *s; + json_t *val; + bool ret = true; + + if (!id || json_is_null(id)) + return false; + + get_currentalgo(algo, sizeof(algo)); + + val = json_object(); + json_object_set(val, "id", id); + json_object_set_new(val, "error", json_null()); + json_object_set_new(val, "result", json_string(algo)); + + s = json_dumps(val, 0); + ret = stratum_send_line(sctx, s); + json_decref(val); + free(s); + + return ret; +} + static bool stratum_get_version(struct stratum_ctx *sctx, json_t *id) { char *s; @@ -1194,36 +2084,64 @@ bool stratum_handle_method(struct stratum_ctx *sctx, const char *s) method = json_string_value(json_object_get(val, "method")); if (!method) goto out; - id = json_object_get(val, "id"); + params = json_object_get(val, "params"); - if (jsonrpc_2) { - if (!strcasecmp(method, "job")) { - ret = stratum_2_job(sctx, params); - goto out; - } - } else { - if (!strcasecmp(method, "mining.notify")) { - ret = stratum_notify(sctx, params); - goto out; - } - if (!strcasecmp(method, "mining.set_difficulty")) { - ret = stratum_set_difficulty(sctx, params); - goto out; - } - if (!strcasecmp(method, "client.reconnect")) { - ret = stratum_reconnect(sctx, params); - goto out; - } - if (!strcasecmp(method, "client.get_version")) { - ret = stratum_get_version(sctx, id); - goto out; - } - if (!strcasecmp(method, "client.show_message")) { - ret = stratum_show_message(sctx, id, params); - goto out; - } - } + if (jsonrpc_2) { + if (!strcasecmp(method, "job")) { + ret = rpc2_stratum_job(sctx, params); + } + goto out; + } + + id = json_object_get(val, "id"); + + if (!strcasecmp(method, "mining.notify")) { + ret = stratum_notify(sctx, params); + goto out; + } + if (!strcasecmp(method, "mining.ping")) { // cgminer 4.7.1+ + if (opt_debug) applog(LOG_DEBUG, "Pool ping"); + ret = stratum_pong(sctx, id); + goto out; + } + if (!strcasecmp(method, "mining.set_difficulty")) { + ret = stratum_set_difficulty(sctx, params); + goto out; + } + if (!strcasecmp(method, "mining.set_extranonce")) { + ret = stratum_parse_extranonce(sctx, params, 0); + goto out; + } + if (!strcasecmp(method, "client.reconnect")) { + ret = stratum_reconnect(sctx, params); + goto out; + } + if (!strcasecmp(method, "client.get_algo")) { + // will prevent wrong algo parameters on a pool, will be used as test on rejects + if (!opt_quiet) applog(LOG_NOTICE, "Pool asked your algo parameter"); + ret = stratum_get_algo(sctx, id, params); + goto out; + } + if (!strcasecmp(method, "client.get_stats")) { + // optional to fill device benchmarks + ret = stratum_get_stats(sctx, id, params); + goto out; + } + if (!strcasecmp(method, "client.get_version")) { + ret = stratum_get_version(sctx, id); + goto out; + } + if (!strcasecmp(method, "client.show_message")) { + ret = stratum_show_message(sctx, id, params); + goto out; + } + + if (!ret) { + // don't fail = disconnect stratum on unknown (and optional?) methods + if (opt_debug) applog(LOG_WARNING, "unknown stratum method %s!", method); + ret = stratum_unknown_method(sctx, id); + } out: if (val) @@ -1236,7 +2154,7 @@ struct thread_q *tq_new(void) { struct thread_q *tq; - tq = calloc(1, sizeof(*tq)); + tq = (struct thread_q*) calloc(1, sizeof(*tq)); if (!tq) return NULL; @@ -1254,7 +2172,7 @@ void tq_free(struct thread_q *tq) if (!tq) return; - list_for_each_entry_safe(ent, iter, &tq->q, q_node) { + list_for_each_entry_safe(ent, iter, &tq->q, q_node, struct tq_ent) { list_del(&ent->q_node); free(ent); } @@ -1291,7 +2209,7 @@ bool tq_push(struct thread_q *tq, void *data) struct tq_ent *ent; bool rc = true; - ent = calloc(1, sizeof(*ent)); + ent = (struct tq_ent*) calloc(1, sizeof(*ent)); if (!ent) return false; @@ -1344,3 +2262,278 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime) pthread_mutex_unlock(&tq->mutex); return rval; } + +/* sprintf can be used in applog */ +static char* format_hash(char* buf, uint8_t *hash) +{ + int len = 0; + for (int i=0; i < 32; i += 4) { + len += sprintf(buf+len, "%02x%02x%02x%02x ", + hash[i], hash[i+1], hash[i+2], hash[i+3]); + } + return buf; +} + +void applog_compare_hash(void *hash, void *hash_ref) +{ + char s[256] = ""; + int len = 0; + uchar* hash1 = (uchar*)hash; + uchar* hash2 = (uchar*)hash_ref; + for (int i=0; i < 32; i += 4) { + const char *color = memcmp(hash1+i, hash2+i, 4) ? CL_WHT : CL_GRY; + len += sprintf(s+len, "%s%02x%02x%02x%02x " CL_GRY, color, + hash1[i], hash1[i+1], hash1[i+2], hash1[i+3]); + s[len] = '\0'; + } + applog(LOG_DEBUG, "%s", s); +} + +void applog_hash(void *hash) +{ + char s[128] = {'\0'}; + applog(LOG_DEBUG, "%s", format_hash(s, (uchar*) hash)); +} + +void applog_hex(void *data, int len) +{ + char* hex = abin2hex((uchar*)data, len); + applog(LOG_DEBUG, "%s", hex); + free(hex); +} + +void applog_hash64(void *hash) +{ + char s[128] = {'\0'}; + char t[128] = {'\0'}; + applog(LOG_DEBUG, "%s %s", format_hash(s, (uchar*)hash), format_hash(t, &((uchar*)hash)[32])); +} + + +#define printpfx(n,h) \ + printf("%s%11s%s: %s\n", CL_CYN, n, CL_N, format_hash(s, (uint8_t*) h)) + +void print_hash_tests(void) +{ + uchar *scratchbuf = NULL; + char hash[128], s[80]; + char buf[192] = { 0 }; + + scratchbuf = (uchar*) calloc(128, 1024); + + printf(CL_WHT "CPU HASH ON EMPTY BUFFER RESULTS:" CL_N "\n\n"); + + memset(buf, 0, sizeof(buf)); + //buf[0] = 1; buf[64] = 2; // for endian tests + + allium_hash(&hash[0], &buf[0]); + printpfx("allium", hash); + + axiomhash(&hash[0], &buf[0]); + printpfx("axiom", hash); + + bastionhash(&hash[0], &buf[0]); + printpfx("bastion", hash); + + blakehash(&hash[0], &buf[0]); + printpfx("blake", hash); + + blakecoinhash(&hash[0], &buf[0]); + printpfx("blakecoin", hash); + + blake2b_hash(&hash[0], &buf[0]); + printpfx("blake2b", hash); + + blake2s_hash(&hash[0], &buf[0]); + printpfx("blake2s", hash); + + bmwhash(&hash[0], &buf[0]); + printpfx("bmw", hash); + + c11hash(&hash[0], &buf[0]); + printpfx("c11", hash); + + cryptolight_hash(&hash[0], &buf[0]); + printpfx("cryptolight", hash); + + cryptonight_hash_v1(&hash[0], &buf[0]); + printpfx("cryptonight", hash); + + decred_hash(&hash[0], &buf[0]); + printpfx("decred", hash); + + droplp_hash(&hash[0], &buf[0]); + printpfx("drop", hash); + + freshhash(&hash[0], &buf[0], 80); + printpfx("fresh", hash); + + geekhash(&hash[0], &buf[0]); + printpfx("geek", hash); + + groestlhash(&hash[0], &buf[0]); + printpfx("groestl", hash); + + heavyhash((uint8_t*) &hash[0], (uint8_t*) &buf[0], 32); + printpfx("heavy", hash); + + keccakhash(&hash[0], &buf[0]); + printpfx("keccak", hash); + + jha_hash(&hash[0], &buf[0]); + printpfx("jha", hash); + + lbry_hash(&hash[0], &buf[0]); + printpfx("lbry", hash); + + luffahash(&hash[0], &buf[0]); + printpfx("luffa", hash); + + lyra2_hash(&hash[0], &buf[0]); + printpfx("lyra2", hash); + + lyra2rev2_hash(&hash[0], &buf[0]); + printpfx("lyra2v2", hash); + + lyra2v3_hash(&hash[0], &buf[0]); + printpfx("lyra2v3", hash); + + cryptonight_hash(&hash[0], &buf[0]); + printpfx("monero", hash); + + myriadhash(&hash[0], &buf[0]); + printpfx("myr-gr", hash); + + neoscrypt((uchar*) &hash[0], (uchar*)&buf[0], 80000620); + printpfx("neoscrypt", hash); + + nist5hash(&hash[0], &buf[0]); + printpfx("nist5", hash); + + pentablakehash(&hash[0], &buf[0]); + printpfx("pentablake", hash); + + phi1612_hash(&hash[0], &buf[0]); + printpfx("phi1612", hash); + + phi2_hash(&hash[0], &buf[0]); + printpfx("phi2", hash); + + pluck_hash((uint32_t*)&hash[0], (uint32_t*)&buf[0], scratchbuf, 128); + memset(&buf[0], 0, sizeof(buf)); + printpfx("pluck", hash); + + init_quarkhash_contexts(); + quarkhash(&hash[0], &buf[0]); + printpfx("quark", hash); + + qubithash(&hash[0], &buf[0]); + printpfx("qubit", hash); + + rf256_hash(&hash[0], &buf[0], 80); + printpfx("rainforest", hash); + + scrypthash(&hash[0], &buf[0], 1024); + printpfx("scrypt", hash); + + scrypthash(&hash[0], &buf[0], 2048); + printpfx("scrypt:2048", hash); + + scryptjanehash(&hash[0], &buf[0], 9); + printpfx("scrypt-jane", hash); + + inkhash(&hash[0], &buf[0]); + printpfx("shavite3", hash); + + sha256d((uint8_t*) &hash[0], (uint8_t*)&buf[0], 64); + printpfx("sha256d", hash); + + blake2b_hash(&hash[0], &buf[0]); + printpfx("sia", hash); + + sibhash(&hash[0], &buf[0]); + printpfx("sib", hash); + + skeinhash(&hash[0], &buf[0]); + printpfx("skein", hash); + + skein2hash(&hash[0], &buf[0]); + printpfx("skein2", hash); + + sonoa_hash(&hash[0], &buf[0]); + printpfx("sonoa", hash); + + s3hash(&hash[0], &buf[0]); + printpfx("s3", hash); + + timetravel_hash(&hash[0], &buf[0]); + printpfx("timetravel", hash); + + bitcore_hash(&hash[0], &buf[0]); + printpfx("bitcore", hash); + + tribus_hash(&hash[0], &buf[0]); + printpfx("tribus", hash); + + veltor_hash(&hash[0], &buf[0]); + printpfx("veltor", hash); + + xevan_hash(&hash[0], &buf[0]); + printpfx("xevan", hash); + + x11evo_hash(&hash[0], &buf[0]); + printpfx("x11evo", hash); + + x11hash(&hash[0], &buf[0]); + printpfx("x11", hash); + + x12hash(&hash[0], &buf[0]); + printpfx("x12", hash); + + x13hash(&hash[0], &buf[0]); + printpfx("x13", hash); + + x14hash(&hash[0], &buf[0]); + printpfx("x14", hash); + + x15hash(&hash[0], &buf[0]); + printpfx("x15", hash); + + x16r_hash(&hash[0], &buf[0]); + //hidden, same as x16rv2 without prevhash + //printpfx("x16r", hash); + + x16rv2_hash(&hash[0], &buf[0]); + printpfx("x16rv2", hash); + + x16s_hash(&hash[0], &buf[0]); + printpfx("x16s", hash); + + x17hash(&hash[0], &buf[0]); + printpfx("x17", hash); + + x20r_hash(&hash[0], &buf[0]); + printpfx("x20r", hash); + + yescrypthash(&hash[0], &buf[0]); + printpfx("yescrypt", hash); + + yescrypt_hash_r8(&buf[0], &hash[0], 80); + printpfx("yescryptr8", hash); + + yescrypt_hash_r16(&buf[0], &hash[0], 80); + printpfx("yescryptr16", hash); + + yescrypt_hash_r32(&buf[0], &hash[0], 80); + printpfx("yescryptr32", hash); + + //zr5hash(&hash[0], &buf[0]); + zr5hash(&hash[0], (uint32_t*) &buf[0]); + memset(buf, 0, sizeof(buf)); + printpfx("zr5", hash); + + printf("\n"); + + free(scratchbuf); +} + diff --git a/x11.c b/x11.c deleted file mode 100644 index 1ab004026..000000000 --- a/x11.c +++ /dev/null @@ -1,196 +0,0 @@ -#include "miner.h" - -#include -#include -#include -#include - -#include "sha3/sph_blake.h" -#include "sha3/sph_bmw.h" -#include "sha3/sph_groestl.h" -#include "sha3/sph_jh.h" -#include "sha3/sph_keccak.h" -#include "sha3/sph_skein.h" -#include "sha3/sph_luffa.h" -#include "sha3/sph_cubehash.h" -#include "sha3/sph_shavite.h" -#include "sha3/sph_simd.h" -#include "sha3/sph_echo.h" - - -void x11_hash(char* output, const char* input) -{ - sph_blake512_context ctx_blake; - sph_bmw512_context ctx_bmw; - sph_groestl512_context ctx_groestl; - sph_skein512_context ctx_skein; - sph_jh512_context ctx_jh; - sph_keccak512_context ctx_keccak; - - sph_luffa512_context ctx_luffa1; - sph_cubehash512_context ctx_cubehash1; - sph_shavite512_context ctx_shavite1; - sph_simd512_context ctx_simd1; - sph_echo512_context ctx_echo1; - - //these uint512 in the c++ source of the client are backed by an array of uint32 - uint32_t hashA[16], hashB[16]; - - sph_blake512_init(&ctx_blake); - sph_blake512 (&ctx_blake, input, 80); - sph_blake512_close (&ctx_blake, hashA); - - sph_bmw512_init(&ctx_bmw); - sph_bmw512 (&ctx_bmw, hashA, 64); - sph_bmw512_close(&ctx_bmw, hashB); - - sph_groestl512_init(&ctx_groestl); - sph_groestl512 (&ctx_groestl, hashB, 64); - sph_groestl512_close(&ctx_groestl, hashA); - - sph_skein512_init(&ctx_skein); - sph_skein512 (&ctx_skein, hashA, 64); - sph_skein512_close (&ctx_skein, hashB); - - sph_jh512_init(&ctx_jh); - sph_jh512 (&ctx_jh, hashB, 64); - sph_jh512_close(&ctx_jh, hashA); - - sph_keccak512_init(&ctx_keccak); - sph_keccak512 (&ctx_keccak, hashA, 64); - sph_keccak512_close(&ctx_keccak, hashB); - - sph_luffa512_init (&ctx_luffa1); - sph_luffa512 (&ctx_luffa1, hashB, 64); - sph_luffa512_close (&ctx_luffa1, hashA); - - sph_cubehash512_init (&ctx_cubehash1); - sph_cubehash512 (&ctx_cubehash1, hashA, 64); - sph_cubehash512_close(&ctx_cubehash1, hashB); - - sph_shavite512_init (&ctx_shavite1); - sph_shavite512 (&ctx_shavite1, hashB, 64); - sph_shavite512_close(&ctx_shavite1, hashA); - - sph_simd512_init (&ctx_simd1); - sph_simd512 (&ctx_simd1, hashA, 64); - sph_simd512_close(&ctx_simd1, hashB); - - sph_echo512_init (&ctx_echo1); - sph_echo512 (&ctx_echo1, hashB, 64); - sph_echo512_close(&ctx_echo1, hashA); - - memcpy(output, hashA, 32); -} - -int scanhash_x11(int thr_id, uint32_t *pdata, const uint32_t *ptarget, - uint32_t max_nonce, uint64_t *hashes_done) -{ - uint32_t n = pdata[19] - 1; - const uint32_t first_nonce = pdata[19]; - const uint32_t Htarg = ptarget[7]; - - uint32_t hash64[8] __attribute__((aligned(32))); - uint32_t endiandata[32]; - - //char testdata[] = {"\x70\x00\x00\x00\x5d\x38\x5b\xa1\x14\xd0\x79\x97\x0b\x29\xa9\x41\x8f\xd0\x54\x9e\x7d\x68\xa9\x5c\x7f\x16\x86\x21\xa3\x14\x20\x10\x00\x00\x00\x00\x57\x85\x86\xd1\x49\xfd\x07\xb2\x2f\x3a\x8a\x34\x7c\x51\x6d\xe7\x05\x2f\x03\x4d\x2b\x76\xff\x68\xe0\xd6\xec\xff\x9b\x77\xa4\x54\x89\xe3\xfd\x51\x17\x32\x01\x1d\xf0\x73\x10\x00"}; - - //we need bigendian data... - //lessons learned: do NOT endianchange directly in pdata, this will all proof-of-works be considered as stale from minerd.... - int kk=0; - for (; kk < 32; kk++) - { - be32enc(&endiandata[kk], ((uint32_t*)pdata)[kk]); - }; - -// if (opt_debug) -// { -// applog(LOG_DEBUG, "Thr: %02d, firstN: %08x, maxN: %08x, ToDo: %d", thr_id, first_nonce, max_nonce, max_nonce-first_nonce); -// } - - /* I'm to lazy to put the loop in an inline function... so dirty copy'n'paste.... */ - /* i know that i could set a variable, but i don't know how the compiler will optimize it, not that then the cpu needs to load the value *everytime* in a register */ - if (ptarget[7]==0) { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - x11_hash((char*) hash64, (const char*) endiandata); - if (((hash64[7]&0xFFFFFFFF)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - x11_hash((char*) hash64, (const char*) endiandata); - if (((hash64[7]&0xFFFFFFF0)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - x11_hash((char*) hash64, (const char*) endiandata); - if (((hash64[7]&0xFFFFFF00)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - else if (ptarget[7]<=0xFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - x11_hash((char*) hash64, (const char*) endiandata); - if (((hash64[7]&0xFFFFF000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else if (ptarget[7]<=0xFFFF) - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - x11_hash((char*) hash64, (const char*) endiandata); - if (((hash64[7]&0xFFFF0000)==0) && - fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - - } - else - { - do { - pdata[19] = ++n; - be32enc(&endiandata[19], n); - x11_hash((char*) hash64, (const char*) endiandata); - if (fulltest(hash64, ptarget)) { - *hashes_done = n - first_nonce + 1; - return true; - } - } while (n < max_nonce && !work_restart[thr_id].restart); - } - - - *hashes_done = n - first_nonce + 1; - pdata[19] = n; - return 0; -} diff --git a/yescrypt/sha256_Y.c b/yescrypt/sha256_Y.c new file mode 100644 index 000000000..2153a15c3 --- /dev/null +++ b/yescrypt/sha256_Y.c @@ -0,0 +1,411 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "sysendian.h" + +#include "sha256_Y.h" +#include "compat.h" + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t _ALIGN(128) W[64], S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; +#if 0 + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +#endif +} + +static unsigned char PAD[64] = { + 0x80, 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, + 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, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX_Y * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + SHA256_Update_Y(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + SHA256_Update_Y(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +SHA256_Init_Y(SHA256_CTX_Y * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void +SHA256_Update_Y(SHA256_CTX_Y * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +SHA256_Final_Y(unsigned char digest[32], SHA256_CTX_Y * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +HMAC_SHA256_Init_Y(HMAC_SHA256_CTX_Y * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init_Y(&ctx->ictx); + SHA256_Update_Y(&ctx->ictx, K, Klen); + SHA256_Final_Y(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init_Y(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update_Y(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init_Y(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update_Y(&ctx->octx, pad, 64); + + /* Clean the stack. */ + //memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +HMAC_SHA256_Update_Y(HMAC_SHA256_CTX_Y * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + SHA256_Update_Y(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +HMAC_SHA256_Final_Y(unsigned char digest[32], HMAC_SHA256_CTX_Y * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final_Y(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update_Y(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final_Y(digest, &ctx->octx); + + /* Clean the stack. */ + //memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX_Y PShctx, hctx; + uint8_t _ALIGN(128) T[32]; + uint8_t _ALIGN(128) U[32]; + uint8_t ivec[4]; + size_t i, clen; + uint64_t j; + int k; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init_Y(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update_Y(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX_Y)); + HMAC_SHA256_Update_Y(&hctx, ivec, 4); + HMAC_SHA256_Final_Y(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init_Y(&hctx, passwd, passwdlen); + HMAC_SHA256_Update_Y(&hctx, U, 32); + HMAC_SHA256_Final_Y(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + //memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX_Y)); +} diff --git a/yescrypt/sha256_Y.h b/yescrypt/sha256_Y.h new file mode 100644 index 000000000..f935cfaaf --- /dev/null +++ b/yescrypt/sha256_Y.h @@ -0,0 +1,62 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256_Y.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include + +#include + +typedef struct SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX_Y; + +typedef struct HMAC_SHA256Context { + SHA256_CTX_Y ictx; + SHA256_CTX_Y octx; +} HMAC_SHA256_CTX_Y; + +void SHA256_Init_Y(SHA256_CTX_Y *); +void SHA256_Update_Y(SHA256_CTX_Y *, const void *, size_t); +void SHA256_Final_Y(unsigned char [32], SHA256_CTX_Y *); +void HMAC_SHA256_Init_Y(HMAC_SHA256_CTX_Y *, const void *, size_t); +void HMAC_SHA256_Update_Y(HMAC_SHA256_CTX_Y *, const void *, size_t); +void HMAC_SHA256_Final_Y(unsigned char [32], HMAC_SHA256_CTX_Y *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/yescrypt/sysendian.h b/yescrypt/sysendian.h new file mode 100644 index 000000000..29933d493 --- /dev/null +++ b/yescrypt/sysendian.h @@ -0,0 +1,124 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +/* If we don't have be64enc, the we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include + +#else + +#include + + + +static __inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static __inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + + + +static __inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static __inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} + + +static __inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static __inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ diff --git a/yescrypt/yescrypt-best.c b/yescrypt/yescrypt-best.c new file mode 100644 index 000000000..4e836215d --- /dev/null +++ b/yescrypt/yescrypt-best.c @@ -0,0 +1,5 @@ +#ifdef __SSE2__ +#include "yescrypt-simd.c" +#else +#include "yescrypt-opt.c" +#endif diff --git a/yescrypt/yescrypt-common.c b/yescrypt/yescrypt-common.c new file mode 100644 index 000000000..a306d6819 --- /dev/null +++ b/yescrypt/yescrypt-common.c @@ -0,0 +1,401 @@ +/*- + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "compat.h" + +#include "yescrypt.h" + +#define BYTES2CHARS(bytes) \ + ((((bytes) * 8) + 5) / 6) + +#define HASH_SIZE 32 /* bytes */ +#define HASH_LEN BYTES2CHARS(HASH_SIZE) /* base-64 chars */ +#define YESCRYPT_FLAGS (YESCRYPT_RW | YESCRYPT_PWXFORM) + +static const char * const itoa64 = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +char *yescrypt_client_key = NULL; +int yescrypt_client_key_len = 0; + +static uint8_t* encode64_uint32(uint8_t* dst, size_t dstlen, uint32_t src, uint32_t srcbits) +{ + uint32_t bit; + + for (bit = 0; bit < srcbits; bit += 6) { + if (dstlen < 1) + return NULL; + *dst++ = itoa64[src & 0x3f]; + dstlen--; + src >>= 6; + } + + return dst; +} + +static uint8_t* encode64(uint8_t* dst, size_t dstlen, const uint8_t* src, size_t srclen) +{ + size_t i; + + for (i = 0; i < srclen; ) { + uint8_t * dnext; + uint32_t value = 0, bits = 0; + do { + value |= (uint32_t)src[i++] << bits; + bits += 8; + } while (bits < 24 && i < srclen); + dnext = encode64_uint32(dst, dstlen, value, bits); + if (!dnext) + return NULL; + dstlen -= dnext - dst; + dst = dnext; + } + + return dst; +} + +static int decode64_one(uint32_t* dst, uint8_t src) +{ + const char * ptr = strchr(itoa64, src); + if (ptr) { + *dst = (uint32_t) (ptr - itoa64); + return 0; + } + *dst = 0; + return -1; +} + +static const uint8_t* decode64_uint32(uint32_t* dst, uint32_t dstbits, const uint8_t* src) +{ + uint32_t bit; + uint32_t value; + + value = 0; + for (bit = 0; bit < dstbits; bit += 6) { + uint32_t one; + if (decode64_one(&one, *src)) { + *dst = 0; + return NULL; + } + src++; + value |= one << bit; + } + + *dst = value; + return src; +} + +uint8_t* yescrypt_r(const yescrypt_shared_t* shared, yescrypt_local_t* local, + const uint8_t* passwd, size_t passwdlen, const uint8_t* setting, uint8_t* buf, size_t buflen) +{ + uint8_t hash[HASH_SIZE]; + const uint8_t * src, * salt; + uint8_t * dst; + size_t prefixlen, saltlen, need; + uint8_t version; + uint64_t N; + uint32_t r, p; + yescrypt_flags_t flags = YESCRYPT_WORM; + + printf("pass1 ..."); + fflush(stdout); + + if (setting[0] != '$' || setting[1] != '7') { + printf("died$7 ..."); + fflush(stdout); + return NULL; + } + + printf("died80 ..."); + fflush(stdout); + + src = setting + 2; + + printf("hello '%p'\n", (char *)src); + fflush(stdout); + + switch ((version = *src)) { + case '$': + printf("died2 ..."); + fflush(stdout); + break; + case 'X': + src++; + flags = YESCRYPT_RW; + printf("died3 ..."); + fflush(stdout); + break; + default: + printf("died4 ..."); + fflush(stdout); + return NULL; + } + + printf("pass2 ..."); + fflush(stdout); + + if (*src != '$') { + uint32_t decoded_flags; + if (decode64_one(&decoded_flags, *src)) { + printf("died5 ..."); + fflush(stdout); + return NULL; + } + flags = decoded_flags; + if (*++src != '$') { + printf("died6 ..."); + fflush(stdout); + return NULL; + } + } + + src++; + + { + uint32_t N_log2; + if (decode64_one(&N_log2, *src)) { + printf("died7 ..."); + return NULL; + } + src++; + N = (uint64_t)1 << N_log2; + } + + src = decode64_uint32(&r, 30, src); + if (!src) { + printf("died6 ..."); + return NULL; + } + + src = decode64_uint32(&p, 30, src); + if (!src) { + printf("died7 ..."); + return NULL; + } + + prefixlen = src - setting; + + salt = src; + src = (uint8_t *)strrchr((char *)salt, '$'); + if (src) + saltlen = src - salt; + else + saltlen = strlen((char *)salt); + + need = prefixlen + saltlen + 1 + HASH_LEN + 1; + if (need > buflen || need < saltlen) { + printf("'%d %d %d'", (int) need, (int) buflen, (int) saltlen); + printf("died8killbuf ..."); + fflush(stdout); + return NULL; + } + + if (yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, N, r, p, 0, flags, hash, sizeof(hash))) { + printf("died10 ..."); + fflush(stdout); + return NULL; + } + + dst = buf; + memcpy(dst, setting, prefixlen + saltlen); + dst += prefixlen + saltlen; + *dst++ = '$'; + + dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); + /* Could zeroize hash[] here, but yescrypt_kdf() doesn't zeroize its + * memory allocations yet anyway. */ + if (!dst || dst >= buf + buflen) { /* Can't happen */ + printf("died11 ..."); + return NULL; + } + + *dst = 0; /* NUL termination */ + + printf("died12 ..."); + fflush(stdout); + + return buf; +} + +uint8_t* yescrypt(const uint8_t* passwd, const uint8_t* setting) +{ + static uint8_t buf[4 + 1 + 5 + 5 + BYTES2CHARS(32) + 1 + HASH_LEN + 1]; + yescrypt_shared_t shared; + yescrypt_local_t local; + uint8_t * retval; + + if (yescrypt_init_shared(&shared, NULL, 0, + 0, 0, 0, YESCRYPT_SHARED_DEFAULTS, 0, NULL, 0)) + return NULL; + if (yescrypt_init_local(&local)) { + yescrypt_free_shared(&shared); + return NULL; + } + retval = yescrypt_r(&shared, &local, + passwd, 80, setting, buf, sizeof(buf)); + //printf("hashse='%s'\n", (char *)retval); + if (yescrypt_free_local(&local)) { + yescrypt_free_shared(&shared); + return NULL; + } + if (yescrypt_free_shared(&shared)) + return NULL; + return retval; +} + +uint8_t* yescrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, yescrypt_flags_t flags, + const uint8_t* src, size_t srclen, uint8_t* buf, size_t buflen) +{ + uint8_t * dst; + size_t prefixlen = 3 + 1 + 5 + 5; + size_t saltlen = BYTES2CHARS(srclen); + size_t need; + + if (p == 1) + flags &= ~YESCRYPT_PARALLEL_SMIX; + + if (flags) { + if (flags & ~0x3f) + return NULL; + + prefixlen++; + if (flags != YESCRYPT_RW) + prefixlen++; + } + + need = prefixlen + saltlen + 1; + if (need > buflen || need < saltlen || saltlen < srclen) + return NULL; + + if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) + return NULL; + + dst = buf; + *dst++ = '$'; + *dst++ = '7'; + if (flags) { + *dst++ = 'X'; /* eXperimental, subject to change */ + if (flags != YESCRYPT_RW) + *dst++ = itoa64[flags]; + } + *dst++ = '$'; + + *dst++ = itoa64[N_log2]; + + dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); + if (!dst) /* Can't happen */ + return NULL; + + dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); + if (!dst) /* Can't happen */ + return NULL; + + dst = encode64(dst, buflen - (dst - buf), src, srclen); + if (!dst || dst >= buf + buflen) /* Can't happen */ + return NULL; + + *dst = 0; /* NUL termination */ + + return buf; +} + +uint8_t* yescrypt_gensalt(uint32_t N_log2, uint32_t r, uint32_t p, yescrypt_flags_t flags, + const uint8_t * src, size_t srclen) +{ + static uint8_t buf[4 + 1 + 5 + 5 + BYTES2CHARS(32) + 1]; + return yescrypt_gensalt_r(N_log2, r, p, flags, src, srclen, + buf, sizeof(buf)); +} + +static int yescrypt_bsty(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + static __thread int initialized = 0; + static __thread yescrypt_shared_t shared; + static __thread yescrypt_local_t local; + int retval; + + if (!initialized) { +/* "shared" could in fact be shared, but it's simpler to keep it private + * along with "local". It's dummy and tiny anyway. */ + if (yescrypt_init_shared(&shared, NULL, 0, + 0, 0, 0, YESCRYPT_SHARED_DEFAULTS, 0, NULL, 0)) + return -1; + if (yescrypt_init_local(&local)) { + yescrypt_free_shared(&shared); + return -1; + } + initialized = 1; + } + retval = yescrypt_kdf(&shared, &local, + passwd, passwdlen, salt, saltlen, N, r, p, 0, YESCRYPT_FLAGS, + buf, buflen); +#if 0 + if (yescrypt_free_local(&local)) { + yescrypt_free_shared(&shared); + return -1; + } + if (yescrypt_free_shared(&shared)) + return -1; + initialized = 0; +#endif + return retval; +} + +/* main hash 80 bytes input */ +void yescrypt_hash(const char *input, char *output, uint32_t len) +{ + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 2048, 8, 1, (uint8_t*)output, 32); +} + +void yescrypt_hash_r8(const char *input, char *output, uint32_t len) +{ + yescrypt_client_key = "Client Key"; + yescrypt_client_key_len = strlen("Client Key"); + yescrypt_bsty((uint8_t*)input, len, (uint8_t *)input, len, 2048, 8, 1, (uint8_t*)output, 32); + +} + +void yescrypt_hash_r16(const char *input, char *output, uint32_t len) +{ + yescrypt_client_key = "Client Key"; + yescrypt_client_key_len = strlen("Client Key"); + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 4096, 16, 1, (uint8_t*)output, 32); + +} + +void yescrypt_hash_r32(const char *input, char *output, uint32_t len) +{ + yescrypt_client_key = "WaviBanana"; + yescrypt_client_key_len = strlen("WaviBanana"); + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 4096, 32, 1, (uint8_t*)output, 32); + +} +/* for util.c test */ +void yescrypthash(void *output, const void *input) +{ + yescrypt_hash((char*) input, (char*) output, 80); +} + diff --git a/yescrypt/yescrypt-opt.c b/yescrypt/yescrypt-opt.c new file mode 100644 index 000000000..8862bce91 --- /dev/null +++ b/yescrypt/yescrypt-opt.c @@ -0,0 +1,939 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include + +#include "sha256_Y.h" +#include "sysendian.h" + +#include "yescrypt-platform.h" + +static __inline void blkcpy(uint64_t * dest, const uint64_t * src, size_t count) +{ + do { + *dest++ = *src++; *dest++ = *src++; + *dest++ = *src++; *dest++ = *src++; + } while (count -= 4); +} + +static __inline void blkxor(uint64_t * dest, const uint64_t * src, size_t count) +{ + do { + *dest++ ^= *src++; *dest++ ^= *src++; + *dest++ ^= *src++; *dest++ ^= *src++; + } while (count -= 4); +} + +typedef union { + uint32_t w[16]; + uint64_t d[8]; +} salsa20_blk_t; + +static __inline void salsa20_simd_shuffle(const salsa20_blk_t * Bin, salsa20_blk_t * Bout) +{ +#define COMBINE(out, in1, in2) \ + Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); + COMBINE(0, 0, 2) + COMBINE(1, 5, 7) + COMBINE(2, 2, 4) + COMBINE(3, 7, 1) + COMBINE(4, 4, 6) + COMBINE(5, 1, 3) + COMBINE(6, 6, 0) + COMBINE(7, 3, 5) +#undef COMBINE +} + +static __inline void salsa20_simd_unshuffle(const salsa20_blk_t * Bin, salsa20_blk_t * Bout) +{ +#define COMBINE(out, in1, in2) \ + Bout->w[out * 2] = (uint32_t) Bin->d[in1]; \ + Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; + COMBINE(0, 0, 6) + COMBINE(1, 5, 3) + COMBINE(2, 2, 0) + COMBINE(3, 7, 5) + COMBINE(4, 4, 2) + COMBINE(5, 1, 7) + COMBINE(6, 6, 4) + COMBINE(7, 3, 1) +#undef COMBINE +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void salsa20_8(uint64_t B[8]) +{ + size_t i; + salsa20_blk_t X; +#define x X.w + + salsa20_simd_unshuffle((const salsa20_blk_t *)B, &X); + + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } +#undef x + + { + salsa20_blk_t Y; + salsa20_simd_shuffle(&X, &Y); + for (i = 0; i < 16; i += 4) { + ((salsa20_blk_t *)B)->w[i] += Y.w[i]; + ((salsa20_blk_t *)B)->w[i + 1] += Y.w[i + 1]; + ((salsa20_blk_t *)B)->w[i + 2] += Y.w[i + 2]; + ((salsa20_blk_t *)B)->w[i + 3] += Y.w[i + 3]; + } + } +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint64_t * Bin, uint64_t * Bout, uint64_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 8], 8); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8], 8); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4], X, 8); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8 + 8], 8); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4 + r * 8], X, 8); + } +} + +/* These are tunable */ +#define S_BITS 8 +#define S_SIMD 2 +#define S_P 4 +#define S_ROUNDS 6 + +/* Number of S-boxes. Not tunable, hard-coded in a few places. */ +#define S_N 2 + +/* Derived values. Not tunable on their own. */ +#define S_SIZE1 (1 << S_BITS) +#define S_MASK ((S_SIZE1 - 1) * S_SIMD * 8) +#define S_MASK2 (((uint64_t)S_MASK << 32) | S_MASK) +#define S_SIZE_ALL (S_N * S_SIZE1 * S_SIMD) +#define S_P_SIZE (S_P * S_SIMD) +#define S_MIN_R ((S_P * S_SIMD + 15) / 16) + +/** + * pwxform(B): + * Transform the provided block using the provided S-boxes. + */ +static void block_pwxform(uint64_t * B, const uint64_t * S) +{ + uint64_t (*X)[S_SIMD] = (uint64_t (*)[S_SIMD])B; + const uint8_t *S0 = (const uint8_t *)S; + const uint8_t *S1 = (const uint8_t *)(S + S_SIZE1 * S_SIMD); + size_t i, j; +#if S_SIMD > 2 + size_t k; +#endif + + for (j = 0; j < S_P; j++) { + uint64_t *Xj = X[j]; + uint64_t x0 = Xj[0]; +#if S_SIMD > 1 + uint64_t x1 = Xj[1]; +#endif + + for (i = 0; i < S_ROUNDS; i++) { + uint64_t x = x0 & S_MASK2; + const uint64_t *p0, *p1; + + p0 = (const uint64_t *)(S0 + (uint32_t)x); + p1 = (const uint64_t *)(S1 + (x >> 32)); + + x0 = (uint64_t)(x0 >> 32) * (uint32_t)x0; + x0 += p0[0]; + x0 ^= p1[0]; + +#if S_SIMD > 1 + x1 = (uint64_t)(x1 >> 32) * (uint32_t)x1; + x1 += p0[1]; + x1 ^= p1[1]; +#endif + +#if S_SIMD > 2 + for (k = 2; k < S_SIMD; k++) { + x = Xj[k]; + + x = (uint64_t)(x >> 32) * (uint32_t)x; + x += p0[k]; + x ^= p1[k]; + + Xj[k] = x; + } +#endif + } + + Xj[0] = x0; +#if S_SIMD > 1 + Xj[1] = x1; +#endif + } +} + +/** + * blockmix_pwxform(Bin, Bout, S, r): + * Compute Bout = BlockMix_pwxform{salsa20/8, S, r}(Bin). The input Bin must + * be 128r bytes in length; the output Bout must also be the same size. + * + * S lacks const qualifier to match blockmix_salsa8()'s prototype, which we + * need to refer to both functions via the same function pointers. + */ +static void blockmix_pwxform(const uint64_t * Bin, uint64_t * Bout, uint64_t * S, size_t r) +{ + size_t r1, r2, i; + + /* Convert 128-byte blocks to (S_P_SIZE * 64-bit) blocks */ + r1 = r * 128 / (S_P_SIZE * 8); + + /* X <-- B_{r1 - 1} */ + blkcpy(Bout, &Bin[(r1 - 1) * S_P_SIZE], S_P_SIZE); + + /* X <-- X \xor B_i */ + blkxor(Bout, Bin, S_P_SIZE); + + /* X <-- H'(X) */ + /* B'_i <-- X */ + block_pwxform(Bout, S); + + /* for i = 0 to r1 - 1 do */ + for (i = 1; i < r1; i++) { + /* X <-- X \xor B_i */ + blkcpy(&Bout[i * S_P_SIZE], &Bout[(i - 1) * S_P_SIZE], + S_P_SIZE); + blkxor(&Bout[i * S_P_SIZE], &Bin[i * S_P_SIZE], S_P_SIZE); + + /* X <-- H'(X) */ + /* B'_i <-- X */ + block_pwxform(&Bout[i * S_P_SIZE], S); + } + + /* Handle partial blocks */ + if (i * S_P_SIZE < r * 16) + blkcpy(&Bout[i * S_P_SIZE], &Bin[i * S_P_SIZE], + r * 16 - i * S_P_SIZE); + + i = (r1 - 1) * S_P_SIZE / 8; + /* Convert 128-byte blocks to 64-byte blocks */ + r2 = r * 2; + + /* B'_i <-- H(B'_i) */ + salsa20_8(&Bout[i * 8]); + i++; + + for (; i < r2; i++) { + /* B'_i <-- H(B'_i \xor B'_{i-1}) */ + blkxor(&Bout[i * 8], &Bout[(i - 1) * 8], 8); + salsa20_8(&Bout[i * 8]); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static __inline uint64_t +integerify(const uint64_t * B, size_t r) +{ +/* + * Our 64-bit words are in host byte order, and word 6 holds the second 32-bit + * word of B_{2r-1} due to SIMD shuffling. The 64-bit value we return is also + * in host byte order, as it should be. + */ + const uint64_t * X = &B[(2 * r - 1) * 8]; + uint32_t lo = (uint32_t) X[0]; + uint32_t hi = (uint32_t) (X[6] >> 32); + return ((uint64_t)hi << 32) + lo; +} + +/** + * smix1(B, r, N, flags, V, NROM, shared, XY, S): + * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be even and + * no smaller than 2. + */ +static void +smix1(uint64_t * B, size_t r, uint64_t N, yescrypt_flags_t flags, + uint64_t * V, uint64_t NROM, const yescrypt_shared_t * shared, + uint64_t * XY, uint64_t * S) +{ + void (*blockmix)(const uint64_t *, uint64_t *, uint64_t *, size_t) = + (S ? blockmix_pwxform : blockmix_salsa8); + const uint64_t * VROM = shared->shared1.aligned; + uint32_t VROM_mask = shared->mask1; + size_t s = 16 * r; + uint64_t * X = V; + uint64_t * Y = &XY[s]; + uint64_t * Z = S ? S : &XY[2 * s]; + uint64_t n, i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&B[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&X[i * 8]; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + blockmix(X, Y, Z, r); + blkcpy(&V[s], Y, s); + + X = XY; + + if (NROM && (VROM_mask & 1)) { + if ((1 & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j = integerify(Y, r) & (NROM - 1); + + /* X <-- H(X \xor VROM_j) */ + blkxor(Y, &VROM[j * s], s); + } + + blockmix(Y, X, Z, r); + + /* 2: for i = 0 to N - 1 do */ + for (n = 1, i = 2; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * s], X, s); + + if ((i & (i - 1)) == 0) + n <<= 1; + + /* j <-- Wrap(Integerify(X), i) */ + j = integerify(X, r) & (n - 1); + j += i - n; + + /* X <-- X \xor V_j */ + blkxor(X, &V[j * s], s); + + /* 4: X <-- H(X) */ + blockmix(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * s], Y, s); + + j = integerify(Y, r); + if (((i + 1) & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j &= NROM - 1; + + /* X <-- H(X \xor VROM_j) */ + blkxor(Y, &VROM[j * s], s); + } else { + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += i + 1 - n; + + /* X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * s], s); + } + + blockmix(Y, X, Z, r); + } + } else { + yescrypt_flags_t rw = flags & YESCRYPT_RW; + + /* 4: X <-- H(X) */ + blockmix(Y, X, Z, r); + + /* 2: for i = 0 to N - 1 do */ + for (n = 1, i = 2; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * s], X, s); + + if (rw) { + if ((i & (i - 1)) == 0) + n <<= 1; + + /* j <-- Wrap(Integerify(X), i) */ + j = integerify(X, r) & (n - 1); + j += i - n; + + /* X <-- X \xor V_j */ + blkxor(X, &V[j * s], s); + } + + /* 4: X <-- H(X) */ + blockmix(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * s], Y, s); + + if (rw) { + /* j <-- Wrap(Integerify(X), i) */ + j = integerify(Y, r) & (n - 1); + j += (i + 1) - n; + + /* X <-- X \xor V_j */ + blkxor(Y, &V[j * s], s); + } + + /* 4: X <-- H(X) */ + blockmix(Y, X, Z, r); + } + } + + /* B' <-- X */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&X[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 8]; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * smix2(B, r, N, Nloop, flags, V, NROM, shared, XY, S): + * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The value Nloop must be even. + */ +static void +smix2(uint64_t * B, size_t r, uint64_t N, uint64_t Nloop, + yescrypt_flags_t flags, + uint64_t * V, uint64_t NROM, const yescrypt_shared_t * shared, + uint64_t * XY, uint64_t * S) +{ + void (*blockmix)(const uint64_t *, uint64_t *, uint64_t *, size_t) = + (S ? blockmix_pwxform : blockmix_salsa8); + const uint64_t * VROM = shared->shared1.aligned; + uint32_t VROM_mask = shared->mask1 | 1; + size_t s = 16 * r; + yescrypt_flags_t rw = flags & YESCRYPT_RW; + uint64_t * X = XY; + uint64_t * Y = &XY[s]; + uint64_t * Z = S ? S : &XY[2 * s]; + uint64_t i, j; + size_t k; + + if (Nloop == 0) + return; + + /* X <-- B' */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&B[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&X[i * 8]; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + + if (NROM) { + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < Nloop; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], X, s); + blockmix(X, Y, Z, r); + + j = integerify(Y, r); + if (((i + 1) & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j &= NROM - 1; + + /* X <-- H(X \xor VROM_j) */ + blkxor(Y, &VROM[j * s], s); + } else { + /* 7: j <-- Integerify(X) mod N */ + j &= N - 1; + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], Y, s); + } + + blockmix(Y, X, Z, r); + } + } else { + /* 6: for i = 0 to N - 1 do */ + i = Nloop / 2; + do { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], X, s); + blockmix(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], Y, s); + blockmix(Y, X, Z, r); + } while (--i); + } + + /* 10: B' <-- X */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&X[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 8]; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * p2floor(x): + * Largest power of 2 not greater than argument. + */ +static uint64_t +p2floor(uint64_t x) +{ + uint64_t y; + while ((y = x & (x - 1))) + x = y; + return x; +} + +/** + * smix(B, r, N, p, t, flags, V, NROM, shared, XY, S): + * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r+64 or (256r+64)*p bytes in length (the larger size is + * required with OpenMP-enabled builds). The value N must be a power of 2 + * greater than 1. + */ +static void +smix(uint64_t * B, size_t r, uint64_t N, uint32_t p, uint32_t t, + yescrypt_flags_t flags, + uint64_t * V, uint64_t NROM, const yescrypt_shared_t * shared, + uint64_t * XY, uint64_t * S) +{ + size_t s = 16 * r; + uint64_t Nchunk = N / p, Nloop_all, Nloop_rw; + uint32_t i; + + Nloop_all = Nchunk; + if (flags & YESCRYPT_RW) { + if (t <= 1) { + if (t) + Nloop_all *= 2; /* 2/3 */ + Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */ + } else { + Nloop_all *= t - 1; + } + } else if (t) { + if (t == 1) + Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */ + Nloop_all *= t; + } + + Nloop_rw = 0; + if (flags & __YESCRYPT_INIT_SHARED) + Nloop_rw = Nloop_all; + else if (flags & YESCRYPT_RW) + Nloop_rw = Nloop_all / p; + + Nchunk &= ~(uint64_t)1; /* round down to even */ + Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */ + Nloop_rw &= ~(uint64_t)1; /* round down to even */ + +#ifdef _OPENMP +#pragma omp parallel if (p > 1) default(none) private(i) shared(B, r, N, p, flags, V, NROM, shared, XY, S, s, Nchunk, Nloop_all, Nloop_rw) + { +#pragma omp for +#endif + for (i = 0; i < p; i++) { + uint64_t Vchunk = i * Nchunk; + uint64_t * Bp = &B[i * s]; + uint64_t * Vp = &V[Vchunk * s]; +#ifdef _OPENMP + uint64_t * XYp = &XY[i * (2 * s + 8)]; +#else + uint64_t * XYp = XY; +#endif + uint64_t Np = (i < p - 1) ? Nchunk : (N - Vchunk); + uint64_t * Sp = S ? &S[i * S_SIZE_ALL] : S; + if (Sp) + smix1(Bp, 1, S_SIZE_ALL / 16, + flags & ~YESCRYPT_PWXFORM, + Sp, NROM, shared, XYp, NULL); + if (!(flags & __YESCRYPT_INIT_SHARED_2)) + smix1(Bp, r, Np, flags, Vp, NROM, shared, XYp, Sp); + smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp, + NROM, shared, XYp, Sp); + } + + if (Nloop_all > Nloop_rw) { +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < p; i++) { + uint64_t * Bp = &B[i * s]; +#ifdef _OPENMP + uint64_t * XYp = &XY[i * (2 * s + 8)]; +#else + uint64_t * XYp = XY; +#endif + uint64_t * Sp = S ? &S[i * S_SIZE_ALL] : S; + smix2(Bp, r, N, Nloop_all - Nloop_rw, + flags & ~YESCRYPT_RW, V, NROM, shared, XYp, Sp); + } + } +#ifdef _OPENMP + } +#endif +} + +/** + * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, + * N, r, p, t, flags, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen), or a revision of scrypt as requested by flags and shared, and + * write the result into buf. The parameters r, p, and buflen must satisfy + * r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N must be a power + * of 2 greater than 1. + * + * t controls computation time while not affecting peak memory usage. shared + * and flags may request special modes as described in yescrypt.h. local is + * the thread-local data structure, allowing to preserve and reuse a memory + * allocation across calls, thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + */ +int +yescrypt_kdf(const yescrypt_shared_t * shared, yescrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, uint32_t t, yescrypt_flags_t flags, + uint8_t * buf, size_t buflen) +{ + yescrypt_region_t tmp; + uint64_t NROM; + size_t B_size, V_size, XY_size, need; + uint64_t * B, * V, * XY, * S; + uint64_t sha256[4]; + + /* + * YESCRYPT_PARALLEL_SMIX is a no-op at p = 1 for its intended purpose, + * so don't let it have side-effects. Without this adjustment, it'd + * enable the SHA-256 password pre-hashing and output post-hashing, + * because any deviation from classic scrypt implies those. + */ + if (p == 1) + flags &= ~YESCRYPT_PARALLEL_SMIX; + + /* Sanity-check parameters */ + if (flags & ~YESCRYPT_KNOWN_FLAGS) { + errno = EINVAL; + return -1; + } +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N <= 1) || (r < 1) || (p < 1)) { + errno = EINVAL; + return -1; + } + if ((flags & YESCRYPT_PARALLEL_SMIX) && (N / p <= 1)) { + errno = EINVAL; + return -1; + } +#if S_MIN_R > 1 + if ((flags & YESCRYPT_PWXFORM) && (r < S_MIN_R)) { + errno = EINVAL; + return -1; + } +#endif + if ((p > SIZE_MAX / ((size_t)256 * r + 64)) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + if (N > UINT64_MAX / ((uint64_t)t + 1)) { + errno = EFBIG; + return -1; + } +#ifdef _OPENMP + if (!(flags & YESCRYPT_PARALLEL_SMIX) && + (N > SIZE_MAX / 128 / (r * p))) { + errno = ENOMEM; + return -1; + } +#endif + if ((flags & YESCRYPT_PWXFORM) && +#ifndef _OPENMP + (flags & YESCRYPT_PARALLEL_SMIX) && +#endif + p > SIZE_MAX / (S_SIZE_ALL * sizeof(*S))) { + errno = ENOMEM; + return -1; + } + + NROM = 0; + if (shared->shared1.aligned) { + NROM = shared->shared1.aligned_size / ((size_t)128 * r); + if (((NROM & (NROM - 1)) != 0) || (NROM <= 1) || + !(flags & YESCRYPT_RW)) { + errno = EINVAL; + return -1; + } + } + + /* Allocate memory */ + V = NULL; + V_size = (size_t)128 * r * N; +#ifdef _OPENMP + if (!(flags & YESCRYPT_PARALLEL_SMIX)) + V_size *= p; +#endif + need = V_size; + if (flags & __YESCRYPT_INIT_SHARED) { + if (local->aligned_size < need) { + if (local->base || local->aligned || + local->base_size || local->aligned_size) { + errno = EINVAL; + return -1; + } + if (!alloc_region(local, need)) + return -1; + } + V = (uint64_t *)local->aligned; + need = 0; + } + B_size = (size_t)128 * r * p; + need += B_size; + if (need < B_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r + 64; +#ifdef _OPENMP + XY_size *= p; +#endif + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (flags & YESCRYPT_PWXFORM) { + size_t S_size = S_SIZE_ALL * sizeof(*S); +#ifdef _OPENMP + S_size *= p; +#else + if (flags & YESCRYPT_PARALLEL_SMIX) + S_size *= p; +#endif + need += S_size; + if (need < S_size) { + errno = ENOMEM; + return -1; + } + } + if (flags & __YESCRYPT_INIT_SHARED) { + if (!alloc_region(&tmp, need)) + return -1; + B = (uint64_t *)tmp.aligned; + XY = (uint64_t *)((uint8_t *)B + B_size); + } else { + init_region(&tmp); + if (local->aligned_size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint64_t *)local->aligned; + V = (uint64_t *)((uint8_t *)B + B_size); + XY = (uint64_t *)((uint8_t *)V + V_size); + } + S = NULL; + if (flags & YESCRYPT_PWXFORM) + S = (uint64_t *)((uint8_t *)XY + XY_size); + + if (t || flags) { + SHA256_CTX_Y ctx; + SHA256_Init_Y(&ctx); + SHA256_Update_Y(&ctx, passwd, passwdlen); + SHA256_Final_Y((uint8_t *)sha256, &ctx); + passwd = (uint8_t *)sha256; + passwdlen = sizeof(sha256); + } + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, + (uint8_t *)B, B_size); + + if (t || flags) + blkcpy(sha256, B, sizeof(sha256) / sizeof(sha256[0])); + + if (p == 1 || (flags & YESCRYPT_PARALLEL_SMIX)) { + smix(B, r, N, p, t, flags, V, NROM, shared, XY, S); + } else { + uint32_t i; + + /* 2: for i = 0 to p - 1 do */ +#ifdef _OPENMP +#pragma omp parallel for default(none) private(i) shared(B, r, N, p, t, flags, V, NROM, shared, XY, S) +#endif + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ +#ifdef _OPENMP + smix(&B[(size_t)16 * r * i], r, N, 1, t, flags, + &V[(size_t)16 * r * i * N], + NROM, shared, + &XY[((size_t)32 * r + 8) * i], + S ? &S[S_SIZE_ALL * i] : S); +#else + smix(&B[(size_t)16 * r * i], r, N, 1, t, flags, V, + NROM, shared, XY, S); +#endif + } + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, (uint8_t *)B, B_size, 1, buf, buflen); + + /* + * Except when computing classic scrypt, allow all computation so far + * to be performed on the client. The final steps below match those of + * SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so + * far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of + * SCRAM's use of SHA-1) would be usable with yescrypt hashes. + */ + if ((t || flags) && buflen == sizeof(sha256)) { + /* Compute ClientKey */ + { + HMAC_SHA256_CTX_Y ctx; + HMAC_SHA256_Init_Y(&ctx, buf, buflen); + if (yescrypt_client_key != NULL) + HMAC_SHA256_Update_Y(&ctx, yescrypt_client_key, + yescrypt_client_key_len); + else + HMAC_SHA256_Update_Y(&ctx, salt, saltlen); + HMAC_SHA256_Final_Y((uint8_t *)sha256, &ctx); + } + /* Compute StoredKey */ + { + SHA256_CTX_Y ctx; + SHA256_Init_Y(&ctx); + SHA256_Update_Y(&ctx, (uint8_t *)sha256, sizeof(sha256)); + SHA256_Final_Y(buf, &ctx); + } + } + + if (free_region(&tmp)) + return -1; + + /* Success! */ + return 0; +} diff --git a/yescrypt/yescrypt-platform.h b/yescrypt/yescrypt-platform.h new file mode 100644 index 000000000..a80640c21 --- /dev/null +++ b/yescrypt/yescrypt-platform.h @@ -0,0 +1,211 @@ +/*- + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef MAP_ANON +#include +#endif + +#include "yescrypt.h" +#define HUGEPAGE_THRESHOLD (12 * 1024 * 1024) + +#ifdef __x86_64__ +#define HUGEPAGE_SIZE (2 * 1024 * 1024) +#else +#undef HUGEPAGE_SIZE +#endif + +static __inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static __inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static void * +alloc_region(yescrypt_region_t * region, size_t size) +{ + size_t base_size = size; + uint8_t * base, * aligned; +#ifdef MAP_ANON + int flags = +#ifdef MAP_NOCORE + MAP_NOCORE | +#endif + MAP_ANON | MAP_PRIVATE; +#if defined(MAP_HUGETLB) && defined(HUGEPAGE_SIZE) + size_t new_size = size; + const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1; + if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) { + flags |= MAP_HUGETLB; +/* + * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of + * huge page size, so let's round up to huge page size here. + */ + new_size = size + hugepage_mask; + new_size &= ~hugepage_mask; + } + base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0); + if (base != MAP_FAILED) { + base_size = new_size; + } else + if (flags & MAP_HUGETLB) { + flags &= ~MAP_HUGETLB; + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + } + +#else + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); +#endif + if (base == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **)&base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) { + errno = ENOMEM; + } else if ((base = malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->base_size = base ? base_size : 0; + region->aligned_size = base ? size : 0; + return aligned; +} + +static __inline void +init_region(yescrypt_region_t * region) +{ + region->base = region->aligned = NULL; + region->base_size = region->aligned_size = 0; +} + +static int +free_region(yescrypt_region_t * region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->base_size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} + +int yescrypt_init_shared(yescrypt_shared_t * shared, const uint8_t * param, size_t paramlen, + uint64_t N, uint32_t r, uint32_t p, yescrypt_init_shared_flags_t flags, uint32_t mask, + uint8_t * buf, size_t buflen) +{ + yescrypt_shared1_t* shared1 = &shared->shared1; + yescrypt_shared_t dummy, half1, half2; + uint8_t salt[32]; + + if (flags & YESCRYPT_SHARED_PREALLOCATED) { + if (!shared1->aligned || !shared1->aligned_size) + return -1; + } else { + init_region(shared1); + } + shared->mask1 = 1; + if (!param && !paramlen && !N && !r && !p && !buf && !buflen) + return 0; + + init_region(&dummy.shared1); + dummy.mask1 = 1; + if (yescrypt_kdf(&dummy, shared1, + param, paramlen, NULL, 0, N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_1, + salt, sizeof(salt))) + goto out; + + half1 = half2 = *shared; + half1.shared1.aligned_size /= 2; + half2.shared1.aligned = (void*) ((size_t)half2.shared1.aligned + half1.shared1.aligned_size); + half2.shared1.aligned_size = half1.shared1.aligned_size; + N /= 2; + + if (p > 1 && yescrypt_kdf(&half1, &half2.shared1, + param, paramlen, salt, sizeof(salt), N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_2, + salt, sizeof(salt))) + goto out; + + if (yescrypt_kdf(&half2, &half1.shared1, + param, paramlen, salt, sizeof(salt), N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_1, + salt, sizeof(salt))) + goto out; + + if (yescrypt_kdf(&half1, &half2.shared1, + param, paramlen, salt, sizeof(salt), N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_1, + buf, buflen)) + goto out; + + shared->mask1 = mask; + + return 0; + +out: + if (!(flags & YESCRYPT_SHARED_PREALLOCATED)) + free_region(shared1); + return -1; +} + +int +yescrypt_free_shared(yescrypt_shared_t * shared) +{ + return free_region(&shared->shared1); +} + +int +yescrypt_init_local(yescrypt_local_t * local) +{ + init_region(local); + return 0; +} + +int +yescrypt_free_local(yescrypt_local_t * local) +{ + return free_region(local); +} diff --git a/yescrypt/yescrypt-simd.c b/yescrypt/yescrypt-simd.c new file mode 100644 index 000000000..dfc9c2c12 --- /dev/null +++ b/yescrypt/yescrypt-simd.c @@ -0,0 +1,1380 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2012-2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +/* + * On 64-bit, enabling SSE4.1 helps our pwxform code indirectly, via avoiding + * gcc bug 54349 (fixed for gcc 4.9+). On 32-bit, it's of direct help. AVX + * and XOP are of further help either way. + */ +#ifndef __SSE4_1__ +#warning "Consider enabling SSE4.1, AVX, or XOP in the C compiler for significantly better performance" +#endif + +#include +#ifdef __XOP__ +#include +#endif + +#include +#include +#include +#include + +#include "sha256_Y.h" +#include "sysendian.h" + +#include "yescrypt.h" +#include "yescrypt-platform.h" + +#include "compat.h" + +#if __STDC_VERSION__ >= 199901L +/* have restrict */ +#elif defined(__GNUC__) +#define restrict __restrict +#else +#define restrict +#endif + +#define PREFETCH(x, hint) _mm_prefetch((const char *)(x), (hint)); +#define PREFETCH_OUT(x, hint) /* disabled */ + +#ifdef __XOP__ +#define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +#else +#define ARX(out, in1, in2, s) \ + { \ + __m128i T = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(T, 32-s)); \ + } +#endif + +#define SALSA20_2ROUNDS \ + /* Operate on "columns" */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ +\ + /* Rearrange data */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ +\ + /* Operate on "rows" */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ +\ + /* Rearrange data */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the salsa20/8 core to the block provided in (X0 ... X3). + */ +#define SALSA20_8_BASE(maybe_decl, out) \ + { \ + maybe_decl Y0 = X0; \ + maybe_decl Y1 = X1; \ + maybe_decl Y2 = X2; \ + maybe_decl Y3 = X3; \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + (out)[0] = X0 = _mm_add_epi32(X0, Y0); \ + (out)[1] = X1 = _mm_add_epi32(X1, Y1); \ + (out)[2] = X2 = _mm_add_epi32(X2, Y2); \ + (out)[3] = X3 = _mm_add_epi32(X3, Y3); \ + } +#define SALSA20_8(out) \ + SALSA20_8_BASE(__m128i, out) + +/** + * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3). + */ +#define SALSA20_8_XOR_ANY(maybe_decl, Z0, Z1, Z2, Z3, out) \ + X0 = _mm_xor_si128(X0, Z0); \ + X1 = _mm_xor_si128(X1, Z1); \ + X2 = _mm_xor_si128(X2, Z2); \ + X3 = _mm_xor_si128(X3, Z3); \ + SALSA20_8_BASE(maybe_decl, out) + +#define SALSA20_8_XOR_MEM(in, out) \ + SALSA20_8_XOR_ANY(__m128i, (in)[0], (in)[1], (in)[2], (in)[3], out) + +#define SALSA20_8_XOR_REG(out) \ + SALSA20_8_XOR_ANY(/* empty */, Y0, Y1, Y2, Y3, out) + +typedef union { + uint32_t w[16]; + __m128i q[4]; +} salsa20_blk_t; + +/** + * blockmix_salsa8(Bin, Bout, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. + */ +static inline void +blockmix_salsa8(const salsa20_blk_t *restrict Bin, + salsa20_blk_t *restrict Bout, size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + r--; + PREFETCH(&Bin[r * 2 + 1], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin[i * 2], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + PREFETCH(&Bin[i * 2 + 1], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r + 1 + i], _MM_HINT_T0) + } + PREFETCH(&Bin[r * 2], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r * 2 + 1], _MM_HINT_T0) + + /* 1: X <-- B_{2r - 1} */ + X0 = Bin[r * 2 + 1].q[0]; + X1 = Bin[r * 2 + 1].q[1]; + X2 = Bin[r * 2 + 1].q[2]; + X3 = Bin[r * 2 + 1].q[3]; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR_MEM(Bin[0].q, Bout[0].q) + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR_MEM(Bin[i * 2 + 1].q, Bout[r + 1 + i].q) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR_MEM(Bin[i * 2].q, Bout[i].q) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR_MEM(Bin[r * 2 + 1].q, Bout[r * 2 + 1].q) +} + +/* + * (V)PSRLDQ and (V)PSHUFD have higher throughput than (V)PSRLQ on some CPUs + * starting with Sandy Bridge. Additionally, PSHUFD uses separate source and + * destination registers, whereas the shifts would require an extra move + * instruction for our code when building without AVX. Unfortunately, PSHUFD + * is much slower on Conroe (4 cycles latency vs. 1 cycle latency for PSRLQ) + * and somewhat slower on some non-Intel CPUs (luckily not including AMD + * Bulldozer and Piledriver). Since for many other CPUs using (V)PSHUFD is a + * win in terms of throughput or/and not needing a move instruction, we + * currently use it despite of the higher latency on some older CPUs. As an + * alternative, the #if below may be patched to only enable use of (V)PSHUFD + * when building with SSE4.1 or newer, which is not available on older CPUs + * where this instruction has higher latency. + */ +#if 1 +#define HI32(X) \ + _mm_shuffle_epi32((X), _MM_SHUFFLE(2,3,0,1)) +#elif 0 +#define HI32(X) \ + _mm_srli_si128((X), 4) +#else +#define HI32(X) \ + _mm_srli_epi64((X), 32) +#endif + +#if defined(__x86_64__) && (defined(__ICC) || defined(__llvm__)) +/* Intel's name, also supported by recent gcc */ +#define EXTRACT64(X) _mm_cvtsi128_si64(X) +#elif defined(__x86_64__) && !defined(_MSC_VER) && !defined(__OPEN64__) +/* gcc got the 'x' name earlier than non-'x', MSVC and Open64 had bugs */ +#define EXTRACT64(X) _mm_cvtsi128_si64x(X) +#elif defined(__x86_64__) && defined(__SSE4_1__) +/* No known bugs for this intrinsic */ +#include +#define EXTRACT64(X) _mm_extract_epi64((X), 0) +#elif defined(__SSE4_1__) +/* 32-bit */ +#include +#if 0 +/* This is currently unused by the code below, which instead uses these two + * intrinsics explicitly when (!defined(__x86_64__) && defined(__SSE4_1__)) */ +#define EXTRACT64(X) \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ + ((uint64_t)(uint32_t)_mm_extract_epi32((X), 1) << 32)) +#endif +#else +/* 32-bit or compilers with known past bugs in _mm_cvtsi128_si64*() */ +#define EXTRACT64(X) \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32)) +#endif + +/* This is tunable */ +#define S_BITS 8 + +/* Not tunable in this implementation, hard-coded in a few places */ +#define S_SIMD 2 +#define S_P 4 + +/* Number of S-boxes. Not tunable by design, hard-coded in a few places. */ +#define S_N 2 + +/* Derived values. Not tunable except via S_BITS above. */ +#define S_SIZE1 (1 << S_BITS) +#define S_MASK ((S_SIZE1 - 1) * S_SIMD * 8) +#define S_MASK2 (((uint64_t)S_MASK << 32) | S_MASK) +#define S_SIZE_ALL (S_N * S_SIZE1 * S_SIMD * 8) + +#if !defined(__x86_64__) && defined(__SSE4_1__) +/* 32-bit with SSE4.1 */ +#define PWXFORM_X_T __m128i +#define PWXFORM_SIMD(X, x, s0, s1) \ + x = _mm_and_si128(X, _mm_set1_epi64x(S_MASK2)); \ + s0 = *(const __m128i *)(S0 + (uint32_t)_mm_cvtsi128_si32(x)); \ + s1 = *(const __m128i *)(S1 + (uint32_t)_mm_extract_epi32(x, 1)); \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, s0); \ + X = _mm_xor_si128(X, s1); +#else +/* 64-bit, or 32-bit without SSE4.1 */ +#define PWXFORM_X_T uint64_t +#define PWXFORM_SIMD(X, x, s0, s1) \ + x = EXTRACT64(X) & S_MASK2; \ + s0 = *(const __m128i *)(S0 + (uint32_t)x); \ + s1 = *(const __m128i *)(S1 + (x >> 32)); \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, s0); \ + X = _mm_xor_si128(X, s1); +#endif + +#define PWXFORM_ROUND \ + PWXFORM_SIMD(X0, x0, s00, s01) \ + PWXFORM_SIMD(X1, x1, s10, s11) \ + PWXFORM_SIMD(X2, x2, s20, s21) \ + PWXFORM_SIMD(X3, x3, s30, s31) + +#define PWXFORM \ + { \ + PWXFORM_X_T x0, x1, x2, x3; \ + __m128i s00, s01, s10, s11, s20, s21, s30, s31; \ + PWXFORM_ROUND PWXFORM_ROUND \ + PWXFORM_ROUND PWXFORM_ROUND \ + PWXFORM_ROUND PWXFORM_ROUND \ + } + +#define XOR4(in) \ + X0 = _mm_xor_si128(X0, (in)[0]); \ + X1 = _mm_xor_si128(X1, (in)[1]); \ + X2 = _mm_xor_si128(X2, (in)[2]); \ + X3 = _mm_xor_si128(X3, (in)[3]); + +#define XOUT(out) \ + (out)[0] = X0; \ + (out)[1] = X1; \ + (out)[2] = X2; \ + (out)[3] = X3; + +/** + * blockmix_pwxform(Bin, Bout, r, S): + * Compute Bout = BlockMix_pwxform{salsa20/8, r, S}(Bin). The input Bin must + * be 128r bytes in length; the output Bout must also be the same size. + */ +static void +blockmix(const salsa20_blk_t *restrict Bin, salsa20_blk_t *restrict Bout, + size_t r, const __m128i *restrict S) +{ + const uint8_t * S0, * S1; + __m128i X0, X1, X2, X3; + size_t i; + + if (!S) { + blockmix_salsa8(Bin, Bout, r); + return; + } + + S0 = (const uint8_t *)S; + S1 = (const uint8_t *)S + S_SIZE_ALL / 2; + + /* Convert 128-byte blocks to 64-byte blocks */ + r *= 2; + + r--; + PREFETCH(&Bin[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + } + PREFETCH_OUT(&Bout[r], _MM_HINT_T0) + + /* X <-- B_{r1 - 1} */ + X0 = Bin[r].q[0]; + X1 = Bin[r].q[1]; + X2 = Bin[r].q[2]; + X3 = Bin[r].q[3]; + + /* for i = 0 to r1 - 1 do */ + for (i = 0; i < r; i++) { + /* X <-- H'(X \xor B_i) */ + XOR4(Bin[i].q) + PWXFORM + /* B'_i <-- X */ + XOUT(Bout[i].q) + } + + /* Last iteration of the loop above */ + XOR4(Bin[i].q) + PWXFORM + + /* B'_i <-- H(B'_i) */ + SALSA20_8(Bout[i].q) +} + +#define XOR4_2(in1, in2) \ + X0 = _mm_xor_si128((in1)[0], (in2)[0]); \ + X1 = _mm_xor_si128((in1)[1], (in2)[1]); \ + X2 = _mm_xor_si128((in1)[2], (in2)[2]); \ + X3 = _mm_xor_si128((in1)[3], (in2)[3]); + +static inline uint32_t +blockmix_salsa8_xor(const salsa20_blk_t *restrict Bin1, + const salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout, + size_t r, int Bin2_in_ROM) +{ + __m128i X0, X1, X2, X3; + size_t i; + + r--; + if (Bin2_in_ROM) { + PREFETCH(&Bin2[r * 2 + 1], _MM_HINT_NTA) + PREFETCH(&Bin1[r * 2 + 1], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i * 2], _MM_HINT_NTA) + PREFETCH(&Bin1[i * 2], _MM_HINT_T0) + PREFETCH(&Bin2[i * 2 + 1], _MM_HINT_NTA) + PREFETCH(&Bin1[i * 2 + 1], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r + 1 + i], _MM_HINT_T0) + } + PREFETCH(&Bin2[r * 2], _MM_HINT_T0) + } else { + PREFETCH(&Bin2[r * 2 + 1], _MM_HINT_T0) + PREFETCH(&Bin1[r * 2 + 1], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i * 2], _MM_HINT_T0) + PREFETCH(&Bin1[i * 2], _MM_HINT_T0) + PREFETCH(&Bin2[i * 2 + 1], _MM_HINT_T0) + PREFETCH(&Bin1[i * 2 + 1], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r + 1 + i], _MM_HINT_T0) + } + PREFETCH(&Bin2[r * 2], _MM_HINT_T0) + } + PREFETCH(&Bin1[r * 2], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r * 2 + 1], _MM_HINT_T0) + + /* 1: X <-- B_{2r - 1} */ + XOR4_2(Bin1[r * 2 + 1].q, Bin2[r * 2 + 1].q) + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[0].q) + SALSA20_8_XOR_MEM(Bin2[0].q, Bout[0].q) + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[i * 2 + 1].q) + SALSA20_8_XOR_MEM(Bin2[i * 2 + 1].q, Bout[r + 1 + i].q) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[i * 2].q) + SALSA20_8_XOR_MEM(Bin2[i * 2].q, Bout[i].q) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[r * 2 + 1].q) + SALSA20_8_XOR_MEM(Bin2[r * 2 + 1].q, Bout[r * 2 + 1].q) + + return _mm_cvtsi128_si32(X0); +} + +static uint32_t +blockmix_xor(const salsa20_blk_t *restrict Bin1, + const salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout, + size_t r, int Bin2_in_ROM, const __m128i *restrict S) +{ + const uint8_t * S0, * S1; + __m128i X0, X1, X2, X3; + size_t i; + + if (!S) + return blockmix_salsa8_xor(Bin1, Bin2, Bout, r, Bin2_in_ROM); + + S0 = (const uint8_t *)S; + S1 = (const uint8_t *)S + S_SIZE_ALL / 2; + + /* Convert 128-byte blocks to 64-byte blocks */ + r *= 2; + + r--; + if (Bin2_in_ROM) { + PREFETCH(&Bin2[r], _MM_HINT_NTA) + PREFETCH(&Bin1[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_NTA) + PREFETCH(&Bin1[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + } + } else { + PREFETCH(&Bin2[r], _MM_HINT_T0) + PREFETCH(&Bin1[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_T0) + PREFETCH(&Bin1[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + } + } + PREFETCH_OUT(&Bout[r], _MM_HINT_T0); + + /* X <-- B_{r1 - 1} */ + XOR4_2(Bin1[r].q, Bin2[r].q) + + /* for i = 0 to r1 - 1 do */ + for (i = 0; i < r; i++) { + /* X <-- H'(X \xor B_i) */ + XOR4(Bin1[i].q) + XOR4(Bin2[i].q) + PWXFORM + /* B'_i <-- X */ + XOUT(Bout[i].q) + } + + /* Last iteration of the loop above */ + XOR4(Bin1[i].q) + XOR4(Bin2[i].q) + PWXFORM + + /* B'_i <-- H(B'_i) */ + SALSA20_8(Bout[i].q) + + return _mm_cvtsi128_si32(X0); +} + +#undef XOR4 +#define XOR4(in, out) \ + (out)[0] = Y0 = _mm_xor_si128((in)[0], (out)[0]); \ + (out)[1] = Y1 = _mm_xor_si128((in)[1], (out)[1]); \ + (out)[2] = Y2 = _mm_xor_si128((in)[2], (out)[2]); \ + (out)[3] = Y3 = _mm_xor_si128((in)[3], (out)[3]); + +static inline uint32_t +blockmix_salsa8_xor_save(const salsa20_blk_t *restrict Bin1, + salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout, + size_t r) +{ + __m128i X0, X1, X2, X3, Y0, Y1, Y2, Y3; + size_t i; + + r--; + PREFETCH(&Bin2[r * 2 + 1], _MM_HINT_T0) + PREFETCH(&Bin1[r * 2 + 1], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i * 2], _MM_HINT_T0) + PREFETCH(&Bin1[i * 2], _MM_HINT_T0) + PREFETCH(&Bin2[i * 2 + 1], _MM_HINT_T0) + PREFETCH(&Bin1[i * 2 + 1], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r + 1 + i], _MM_HINT_T0) + } + PREFETCH(&Bin2[r * 2], _MM_HINT_T0) + PREFETCH(&Bin1[r * 2], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r], _MM_HINT_T0) + PREFETCH_OUT(&Bout[r * 2 + 1], _MM_HINT_T0) + + /* 1: X <-- B_{2r - 1} */ + XOR4_2(Bin1[r * 2 + 1].q, Bin2[r * 2 + 1].q) + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[0].q, Bin2[0].q) + SALSA20_8_XOR_REG(Bout[0].q) + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[i * 2 + 1].q, Bin2[i * 2 + 1].q) + SALSA20_8_XOR_REG(Bout[r + 1 + i].q) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[i * 2].q, Bin2[i * 2].q) + SALSA20_8_XOR_REG(Bout[i].q) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1[r * 2 + 1].q, Bin2[r * 2 + 1].q) + SALSA20_8_XOR_REG(Bout[r * 2 + 1].q) + + return _mm_cvtsi128_si32(X0); +} + +#define XOR4_Y \ + X0 = _mm_xor_si128(X0, Y0); \ + X1 = _mm_xor_si128(X1, Y1); \ + X2 = _mm_xor_si128(X2, Y2); \ + X3 = _mm_xor_si128(X3, Y3); + +static uint32_t +blockmix_xor_save(const salsa20_blk_t *restrict Bin1, + salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout, + size_t r, const __m128i *restrict S) +{ + const uint8_t * S0, * S1; + __m128i X0, X1, X2, X3, Y0, Y1, Y2, Y3; + size_t i; + + if (!S) + return blockmix_salsa8_xor_save(Bin1, Bin2, Bout, r); + + S0 = (const uint8_t *)S; + S1 = (const uint8_t *)S + S_SIZE_ALL / 2; + + /* Convert 128-byte blocks to 64-byte blocks */ + r *= 2; + + r--; + PREFETCH(&Bin2[r], _MM_HINT_T0) + PREFETCH(&Bin1[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_T0) + PREFETCH(&Bin1[i], _MM_HINT_T0) + PREFETCH_OUT(&Bout[i], _MM_HINT_T0) + } + PREFETCH_OUT(&Bout[r], _MM_HINT_T0); + + /* X <-- B_{r1 - 1} */ + XOR4_2(Bin1[r].q, Bin2[r].q) + + /* for i = 0 to r1 - 1 do */ + for (i = 0; i < r; i++) { + XOR4(Bin1[i].q, Bin2[i].q) + /* X <-- H'(X \xor B_i) */ + XOR4_Y + PWXFORM + /* B'_i <-- X */ + XOUT(Bout[i].q) + } + + /* Last iteration of the loop above */ + XOR4(Bin1[i].q, Bin2[i].q) + XOR4_Y + PWXFORM + + /* B'_i <-- H(B'_i) */ + SALSA20_8(Bout[i].q) + + return _mm_cvtsi128_si32(X0); +} + +#undef ARX +#undef SALSA20_2ROUNDS +#undef SALSA20_8 +#undef SALSA20_8_XOR_ANY +#undef SALSA20_8_XOR_MEM +#undef SALSA20_8_XOR_REG +#undef PWXFORM_SIMD_1 +#undef PWXFORM_SIMD_2 +#undef PWXFORM_ROUND +#undef PWXFORM +#undef OUT +#undef XOR4 +#undef XOR4_2 +#undef XOR4_Y + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint32_t +integerify(const salsa20_blk_t * B, size_t r) +{ + return B[2 * r - 1].w[0]; +} + +/** + * smix1(B, r, N, flags, V, NROM, shared, XY, S): + * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 128r bytes in length. The value N must be even and no + * smaller than 2. The array V must be aligned to a multiple of 64 bytes, and + * arrays B and XY to a multiple of at least 16 bytes (aligning them to 64 + * bytes as well saves cache lines, but might result in cache bank conflicts). + */ +static void +smix1(uint8_t * B, size_t r, uint32_t N, yescrypt_flags_t flags, + salsa20_blk_t * V, uint32_t NROM, const yescrypt_shared_t * shared, + salsa20_blk_t * XY, void * S) +{ + const salsa20_blk_t * VROM = shared->shared1.aligned; + uint32_t VROM_mask = shared->mask1; + size_t s = 2 * r; + salsa20_blk_t * X = V, * Y; + uint32_t i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X[k].w[i] = le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + if (NROM && (VROM_mask & 1)) { + uint32_t n; + salsa20_blk_t * V_n; + const salsa20_blk_t * V_j; + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V[s]; + blockmix(X, Y, r, S); + + X = &V[2 * s]; + if ((1 & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j = integerify(Y, r) & (NROM - 1); + V_j = &VROM[j * s]; + + /* X <-- H(X \xor VROM_j) */ + j = blockmix_xor(Y, V_j, X, r, 1, S); + } else { + /* X <-- H(X) */ + blockmix(Y, X, r, S); + j = integerify(X, r); + } + + for (n = 2; n < N; n <<= 1) { + uint32_t m = (n < N / 2) ? n : (N - 1 - n); + + V_n = &V[n * s]; + + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < m; i += 2) { + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += i - 1; + V_j = &V[j * s]; + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V_n[i * s]; + j = blockmix_xor(X, V_j, Y, r, 0, S); + + if (((n + i) & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j &= NROM - 1; + V_j = &VROM[j * s]; + } else { + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += i; + V_j = &V[j * s]; + } + + /* X <-- H(X \xor VROM_j) */ + X = &V_n[(i + 1) * s]; + j = blockmix_xor(Y, V_j, X, r, 1, S); + } + } + + n >>= 1; + + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += N - 2 - n; + V_j = &V[j * s]; + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V[(N - 1) * s]; + j = blockmix_xor(X, V_j, Y, r, 0, S); + + if (((N - 1) & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j &= NROM - 1; + V_j = &VROM[j * s]; + } else { + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += N - 1 - n; + V_j = &V[j * s]; + } + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + X = XY; + blockmix_xor(Y, V_j, X, r, 1, S); + } else if (flags & YESCRYPT_RW) { + uint32_t n; + salsa20_blk_t * V_n, * V_j; + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V[s]; + blockmix(X, Y, r, S); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = &V[2 * s]; + blockmix(Y, X, r, S); + j = integerify(X, r); + + for (n = 2; n < N; n <<= 1) { + uint32_t m = (n < N / 2) ? n : (N - 1 - n); + + V_n = &V[n * s]; + + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < m; i += 2) { + Y = &V_n[i * s]; + + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += i - 1; + V_j = &V[j * s]; + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + j = blockmix_xor(X, V_j, Y, r, 0, S); + + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += i; + V_j = &V[j * s]; + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = &V_n[(i + 1) * s]; + j = blockmix_xor(Y, V_j, X, r, 0, S); + } + } + + n >>= 1; + + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += N - 2 - n; + V_j = &V[j * s]; + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V[(N - 1) * s]; + j = blockmix_xor(X, V_j, Y, r, 0, S); + + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += N - 1 - n; + V_j = &V[j * s]; + + /* X <-- X \xor V_j */ + /* 4: X <-- H(X) */ + X = XY; + blockmix_xor(Y, V_j, X, r, 0, S); + } else { + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < N - 1; i += 2) { + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V[i * s]; + blockmix(X, Y, r, S); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = &V[(i + 1) * s]; + blockmix(Y, X, r, S); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = &V[i * s]; + blockmix(X, Y, r, S); + + /* 4: X <-- H(X) */ + X = XY; + blockmix(Y, X, r, S); + } + + /* B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], X[k].w[i]); + } + } +} + +/** + * smix2(B, r, N, Nloop, flags, V, NROM, shared, XY, S): + * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r bytes in length. The value N must be a power of 2 + * greater than 1. The value Nloop must be even. The array V must be aligned + * to a multiple of 64 bytes, and arrays B and XY to a multiple of at least 16 + * bytes (aligning them to 64 bytes as well saves cache lines, but might result + * in cache bank conflicts). + */ +static void +smix2(uint8_t * B, size_t r, uint32_t N, uint64_t Nloop, + yescrypt_flags_t flags, salsa20_blk_t * V, uint32_t NROM, + const yescrypt_shared_t * shared, salsa20_blk_t * XY, void * S) +{ + const salsa20_blk_t * VROM = shared->shared1.aligned; + uint32_t VROM_mask = shared->mask1; + size_t s = 2 * r; + salsa20_blk_t * X = XY, * Y = &XY[s]; + uint64_t i; + uint32_t j; + size_t k; + + if (Nloop == 0) + return; + + /* X <-- B' */ + /* 3: V_i <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X[k].w[i] = le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + i = Nloop / 2; + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + +/* + * Normally, NROM implies YESCRYPT_RW, but we check for these separately + * because YESCRYPT_PARALLEL_SMIX resets YESCRYPT_RW for the smix2() calls + * operating on the entire V. + */ + if (NROM && (flags & YESCRYPT_RW)) { + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < Nloop; i += 2) { + salsa20_blk_t * V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* V_j <-- Xprev \xor V_j */ + /* j <-- Integerify(X) mod NROM */ + j = blockmix_xor_save(X, V_j, Y, r, S); + + if (((i + 1) & VROM_mask) == 1) { + const salsa20_blk_t * VROM_j; + + j &= NROM - 1; + VROM_j = &VROM[j * s]; + + /* X <-- H(X \xor VROM_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_xor(Y, VROM_j, X, r, 1, S); + } else { + j &= N - 1; + V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* V_j <-- Xprev \xor V_j */ + /* j <-- Integerify(X) mod NROM */ + j = blockmix_xor_save(Y, V_j, X, r, S); + } + j &= N - 1; + V_j = &V[j * s]; + } + } else if (NROM) { + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < Nloop; i += 2) { + const salsa20_blk_t * V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* V_j <-- Xprev \xor V_j */ + /* j <-- Integerify(X) mod NROM */ + j = blockmix_xor(X, V_j, Y, r, 0, S); + + if (((i + 1) & VROM_mask) == 1) { + j &= NROM - 1; + V_j = &VROM[j * s]; + } else { + j &= N - 1; + V_j = &V[j * s]; + } + + /* X <-- H(X \xor VROM_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_xor(Y, V_j, X, r, 1, S); + j &= N - 1; + V_j = &V[j * s]; + } + } else if (flags & YESCRYPT_RW) { + /* 6: for i = 0 to N - 1 do */ + do { + salsa20_blk_t * V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* V_j <-- Xprev \xor V_j */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_xor_save(X, V_j, Y, r, S); + j &= N - 1; + V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* V_j <-- Xprev \xor V_j */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_xor_save(Y, V_j, X, r, S); + j &= N - 1; + } while (--i); + } else { + /* 6: for i = 0 to N - 1 do */ + do { + const salsa20_blk_t * V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_xor(X, V_j, Y, r, 0, S); + j &= N - 1; + V_j = &V[j * s]; + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_xor(Y, V_j, X, r, 0, S); + j &= N - 1; + } while (--i); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], X[k].w[i]); + } + } +} + +/** + * p2floor(x): + * Largest power of 2 not greater than argument. + */ +static uint64_t +p2floor(uint64_t x) +{ + uint64_t y; + while ((y = x & (x - 1))) + x = y; + return x; +} + +/** + * smix(B, r, N, p, t, flags, V, NROM, shared, XY, S): + * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage XY + * must be 256r or 256rp bytes in length (the larger size is required with + * OpenMP-enabled builds). The value N must be a power of 2 greater than 1. + * The array V must be aligned to a multiple of 64 bytes, and arrays B and + * XY to a multiple of at least 16 bytes (aligning them to 64 bytes as well + * saves cache lines and helps avoid false sharing in OpenMP-enabled builds + * when p > 1, but it might also result in cache bank conflicts). + */ +static void +smix(uint8_t * B, size_t r, uint32_t N, uint32_t p, uint32_t t, + yescrypt_flags_t flags, + salsa20_blk_t * V, uint32_t NROM, const yescrypt_shared_t * shared, + salsa20_blk_t * XY, void * S) +{ + size_t s = 2 * r; + uint32_t Nchunk = N / p; + uint64_t Nloop_all, Nloop_rw; + uint32_t i; + + Nloop_all = Nchunk; + if (flags & YESCRYPT_RW) { + if (t <= 1) { + if (t) + Nloop_all *= 2; /* 2/3 */ + Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */ + } else { + Nloop_all *= t - 1; + } + } else if (t) { + if (t == 1) + Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */ + Nloop_all *= t; + } + + Nloop_rw = 0; + if (flags & __YESCRYPT_INIT_SHARED) + Nloop_rw = Nloop_all; + else if (flags & YESCRYPT_RW) + Nloop_rw = Nloop_all / p; + + Nchunk &= ~(uint32_t)1; /* round down to even */ + Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */ + Nloop_rw &= ~(uint64_t)1; /* round down to even */ + +#ifdef _OPENMP +#pragma omp parallel if (p > 1) default(none) private(i) shared(B, r, N, p, flags, V, NROM, shared, XY, S, s, Nchunk, Nloop_all, Nloop_rw) + { +#pragma omp for +#endif + for (i = 0; i < p; i++) { + uint32_t Vchunk = i * Nchunk; + uint8_t * Bp = &B[128 * r * i]; + salsa20_blk_t * Vp = &V[Vchunk * s]; +#ifdef _OPENMP + salsa20_blk_t * XYp = &XY[i * (2 * s)]; +#else + salsa20_blk_t * XYp = XY; +#endif + uint32_t Np = (i < p - 1) ? Nchunk : (N - Vchunk); + void * Sp = S ? ((uint8_t *)S + i * S_SIZE_ALL) : S; + if (Sp) + smix1(Bp, 1, S_SIZE_ALL / 128, + flags & ~YESCRYPT_PWXFORM, + Sp, NROM, shared, XYp, NULL); + if (!(flags & __YESCRYPT_INIT_SHARED_2)) + smix1(Bp, r, Np, flags, Vp, NROM, shared, XYp, Sp); + smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp, + NROM, shared, XYp, Sp); + } + + if (Nloop_all > Nloop_rw) { +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < p; i++) { + uint8_t * Bp = &B[128 * r * i]; +#ifdef _OPENMP + salsa20_blk_t * XYp = &XY[i * (2 * s)]; +#else + salsa20_blk_t * XYp = XY; +#endif + void * Sp = S ? ((uint8_t *)S + i * S_SIZE_ALL) : S; + smix2(Bp, r, N, Nloop_all - Nloop_rw, + flags & ~YESCRYPT_RW, V, NROM, shared, XYp, Sp); + } + } +#ifdef _OPENMP + } +#endif +} + +/** + * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, + * N, r, p, t, flags, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen), or a revision of scrypt as requested by flags and shared, and + * write the result into buf. The parameters r, p, and buflen must satisfy + * r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N must be a power + * of 2 greater than 1. (This optimized implementation currently additionally + * limits N to the range from 8 to 2^31, but other implementation might not.) + * + * t controls computation time while not affecting peak memory usage. shared + * and flags may request special modes as described in yescrypt.h. local is + * the thread-local data structure, allowing to preserve and reuse a memory + * allocation across calls, thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + */ +int +yescrypt_kdf(const yescrypt_shared_t * shared, yescrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, uint32_t t, yescrypt_flags_t flags, + uint8_t * buf, size_t buflen) +{ + uint8_t _ALIGN(128) sha256[32]; + yescrypt_region_t tmp; + uint64_t NROM; + size_t B_size, V_size, XY_size, need; + uint8_t * B, * S; + salsa20_blk_t * V, * XY; + + /* + * YESCRYPT_PARALLEL_SMIX is a no-op at p = 1 for its intended purpose, + * so don't let it have side-effects. Without this adjustment, it'd + * enable the SHA-256 password pre-hashing and output post-hashing, + * because any deviation from classic scrypt implies those. + */ + if (p == 1) + flags &= ~YESCRYPT_PARALLEL_SMIX; + + /* Sanity-check parameters */ + if (flags & ~YESCRYPT_KNOWN_FLAGS) { + errno = EINVAL; + return -1; + } +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N <= 7) || (r < 1) || (p < 1)) { + errno = EINVAL; + return -1; + } + if ((flags & YESCRYPT_PARALLEL_SMIX) && (N / p <= 7)) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 256 / p) || + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } +#ifdef _OPENMP + if (!(flags & YESCRYPT_PARALLEL_SMIX) && + (N > SIZE_MAX / 128 / (r * p))) { + errno = ENOMEM; + return -1; + } +#endif + if ((flags & YESCRYPT_PWXFORM) && +#ifndef _OPENMP + (flags & YESCRYPT_PARALLEL_SMIX) && +#endif + p > SIZE_MAX / S_SIZE_ALL) { + errno = ENOMEM; + return -1; + } + + NROM = 0; + if (shared->shared1.aligned) { + NROM = shared->shared1.aligned_size / ((size_t)128 * r); + if (NROM > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((NROM & (NROM - 1)) != 0) || (NROM <= 7) || + !(flags & YESCRYPT_RW)) { + errno = EINVAL; + return -1; + } + } + + /* Allocate memory */ + V = NULL; + V_size = (size_t)128 * r * N; +#ifdef _OPENMP + if (!(flags & YESCRYPT_PARALLEL_SMIX)) + V_size *= p; +#endif + need = V_size; + if (flags & __YESCRYPT_INIT_SHARED) { + if (local->aligned_size < need) { + if (local->base || local->aligned || + local->base_size || local->aligned_size) { + errno = EINVAL; + return -1; + } + if (!alloc_region(local, need)) + return -1; + } + V = (salsa20_blk_t *)local->aligned; + need = 0; + } + B_size = (size_t)128 * r * p; + need += B_size; + if (need < B_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r; +#ifdef _OPENMP + XY_size *= p; +#endif + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (flags & YESCRYPT_PWXFORM) { + size_t S_size = S_SIZE_ALL; +#ifdef _OPENMP + S_size *= p; +#else + if (flags & YESCRYPT_PARALLEL_SMIX) + S_size *= p; +#endif + need += S_size; + if (need < S_size) { + errno = ENOMEM; + return -1; + } + } + if (flags & __YESCRYPT_INIT_SHARED) { + if (!alloc_region(&tmp, need)) + return -1; + B = (uint8_t *)tmp.aligned; + XY = (salsa20_blk_t *)((uint8_t *)B + B_size); + } else { + init_region(&tmp); + if (local->aligned_size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint8_t *)local->aligned; + V = (salsa20_blk_t *)((uint8_t *)B + B_size); + XY = (salsa20_blk_t *)((uint8_t *)V + V_size); + } + S = NULL; + if (flags & YESCRYPT_PWXFORM) + S = (uint8_t *)XY + XY_size; + + if (t || flags) { + SHA256_CTX_Y ctx; + SHA256_Init_Y(&ctx); + SHA256_Update_Y(&ctx, passwd, passwdlen); + SHA256_Final_Y(sha256, &ctx); + passwd = sha256; + passwdlen = sizeof(sha256); + } + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + if (t || flags) + memcpy(sha256, B, sizeof(sha256)); + + if (p == 1 || (flags & YESCRYPT_PARALLEL_SMIX)) { + smix(B, r, N, p, t, flags, V, NROM, shared, XY, S); + } else { + uint32_t i; + + /* 2: for i = 0 to p - 1 do */ +#ifdef _OPENMP +#pragma omp parallel for default(none) private(i) shared(B, r, N, p, t, flags, V, NROM, shared, XY, S) +#endif + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ +#ifdef _OPENMP + smix(&B[(size_t)128 * r * i], r, N, 1, t, flags, + &V[(size_t)2 * r * i * N], + NROM, shared, + &XY[(size_t)4 * r * i], + S ? &S[S_SIZE_ALL * i] : S); +#else + smix(&B[(size_t)128 * r * i], r, N, 1, t, flags, V, + NROM, shared, XY, S); +#endif + } + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* + * Except when computing classic scrypt, allow all computation so far + * to be performed on the client. The final steps below match those of + * SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so + * far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of + * SCRAM's use of SHA-1) would be usable with yescrypt hashes. + */ + if ((t || flags) && buflen == sizeof(sha256)) { + /* Compute ClientKey */ + { + HMAC_SHA256_CTX_Y ctx; + HMAC_SHA256_Init_Y(&ctx, buf, buflen); + if (yescrypt_client_key != NULL) + HMAC_SHA256_Update_Y(&ctx, yescrypt_client_key, + yescrypt_client_key_len); + else + /* GlobalBoost-Y buggy yescrypt */ + HMAC_SHA256_Update_Y(&ctx, salt, saltlen); + HMAC_SHA256_Final_Y(sha256, &ctx); + } + /* Compute StoredKey */ + { + SHA256_CTX_Y ctx; + SHA256_Init_Y(&ctx); + SHA256_Update_Y(&ctx, sha256, sizeof(sha256)); + SHA256_Final_Y(buf, &ctx); + } + } + + if (free_region(&tmp)) + return -1; + + /* Success! */ + return 0; +} diff --git a/yescrypt/yescrypt.h b/yescrypt/yescrypt.h new file mode 100644 index 000000000..1775a48d8 --- /dev/null +++ b/yescrypt/yescrypt.h @@ -0,0 +1,379 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#ifndef YESCRYPT_H +#define YESCRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include /* for size_t */ + +void yescrypt_hash(const char* input, char* output, uint32_t len); +void yescrypt_hash_r8(const char* input, char* output, uint32_t len); +void yescrypt_hash_r16(const char* input, char* output, uint32_t len); +void yescrypt_hash_r32(const char* input, char* output, uint32_t len); + + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as buf is local to the thread. + */ +extern int crypto_scrypt(const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +/** + * Internal type used by the memory allocator. Please do not use it directly. + * Use yescrypt_shared_t and yescrypt_local_t as appropriate instead, since + * they might differ from each other in a future version. + */ +typedef struct { + void * base, * aligned; + size_t base_size, aligned_size; +} yescrypt_region_t; + +/** + * Types for shared (ROM) and thread-local (RAM) data structures. + */ +typedef yescrypt_region_t yescrypt_shared1_t; +typedef struct { + yescrypt_shared1_t shared1; + uint32_t mask1; +} yescrypt_shared_t; +typedef yescrypt_region_t yescrypt_local_t; + +/** + * Possible values for yescrypt_init_shared()'s flags argument. + */ +typedef enum { + YESCRYPT_SHARED_DEFAULTS = 0, + YESCRYPT_SHARED_PREALLOCATED = 0x100 +} yescrypt_init_shared_flags_t; + +/** + * Possible values for the flags argument of yescrypt_kdf(), + * yescrypt_gensalt_r(), yescrypt_gensalt(). These may be OR'ed together, + * except that YESCRYPT_WORM and YESCRYPT_RW are mutually exclusive. + * Please refer to the description of yescrypt_kdf() below for the meaning of + * these flags. + */ +typedef enum { +/* public */ + YESCRYPT_WORM = 0, + YESCRYPT_RW = 1, + YESCRYPT_PARALLEL_SMIX = 2, + YESCRYPT_PWXFORM = 4, +/* private */ + __YESCRYPT_INIT_SHARED_1 = 0x10000, + __YESCRYPT_INIT_SHARED_2 = 0x20000, + __YESCRYPT_INIT_SHARED = 0x30000 +} yescrypt_flags_t; + +#define YESCRYPT_KNOWN_FLAGS \ + (YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | YESCRYPT_PWXFORM | \ + __YESCRYPT_INIT_SHARED) + +/** + * yescrypt_init_shared(shared, param, paramlen, N, r, p, flags, mask, + * buf, buflen): + * Optionally allocate memory for and initialize the shared (ROM) data + * structure. The parameters N, r, and p must satisfy the same conditions as + * with crypto_scrypt(). param and paramlen specify a local parameter with + * which the ROM is seeded. If buf is not NULL, then it is used to return + * buflen bytes of message digest for the initialized ROM (the caller may use + * this to verify that the ROM has been computed in the same way that it was on + * a previous run). + * + * Return 0 on success; or -1 on error. + * + * If bit YESCRYPT_SHARED_PREALLOCATED in flags is set, then memory for the + * ROM is assumed to have been preallocated by the caller, with + * shared->shared1.aligned being the start address of the ROM and + * shared->shared1.aligned_size being its size (which must be consistent with + * N, r, and p). This may be used e.g. when the ROM is to be placed in a SysV + * shared memory segment allocated by the caller. + * + * mask controls the frequency of ROM accesses by yescrypt_kdf(). Normally it + * should be set to 1, to interleave RAM and ROM accesses, which works well + * when both regions reside in the machine's RAM anyway. Other values may be + * used e.g. when the ROM is memory-mapped from a disk file. Recommended mask + * values are powers of 2 minus 1 or minus 2. Here's the effect of some mask + * values: + * mask value ROM accesses in SMix 1st loop ROM accesses in SMix 2nd loop + * 0 0 1/2 + * 1 1/2 1/2 + * 2 0 1/4 + * 3 1/4 1/4 + * 6 0 1/8 + * 7 1/8 1/8 + * 14 0 1/16 + * 15 1/16 1/16 + * 1022 0 1/1024 + * 1023 1/1024 1/1024 + * + * Actual computation of the ROM contents may be avoided, if you don't intend + * to use a ROM but need a dummy shared structure, by calling this function + * with NULL, 0, 0, 0, 0, YESCRYPT_SHARED_DEFAULTS, 0, NULL, 0 for the + * arguments starting with param and on. + * + * MT-safe as long as shared is local to the thread. + */ +extern int yescrypt_init_shared(yescrypt_shared_t * __shared, + const uint8_t * __param, size_t __paramlen, + uint64_t __N, uint32_t __r, uint32_t __p, + yescrypt_init_shared_flags_t __flags, uint32_t __mask, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt_free_shared(shared): + * Free memory that had been allocated with yescrypt_init_shared(). + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as shared is local to the thread. + */ +extern int yescrypt_free_shared(yescrypt_shared_t * __shared); + +/** + * yescrypt_init_local(local): + * Initialize the thread-local (RAM) data structure. Actual memory allocation + * is currently fully postponed until a call to yescrypt_kdf() or yescrypt_r(). + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yescrypt_init_local(yescrypt_local_t * __local); + +/** + * yescrypt_free_local(local): + * Free memory that may have been allocated for an initialized thread-local + * (RAM) data structure. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yescrypt_free_local(yescrypt_local_t * __local); + +/** + * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, + * N, r, p, t, flags, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen), or a revision of scrypt as requested by flags and shared, and + * write the result into buf. The parameters N, r, p, and buflen must satisfy + * the same conditions as with crypto_scrypt(). t controls computation time + * while not affecting peak memory usage. shared and flags may request + * special modes as described below. local is the thread-local data + * structure, allowing to preserve and reuse a memory allocation across calls, + * thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + * + * t controls computation time. t = 0 is optimal in terms of achieving the + * highest area-time for ASIC attackers. Thus, higher computation time, if + * affordable, is best achieved by increasing N rather than by increasing t. + * However, if the higher memory usage (which goes along with higher N) is not + * affordable, or if fine-tuning of the time is needed (recall that N must be a + * power of 2), then t = 1 or above may be used to increase time while staying + * at the same peak memory usage. t = 1 increases the time by 25% and + * decreases the normalized area-time to 96% of optimal. (Of course, in + * absolute terms the area-time increases with higher t. It's just that it + * would increase slightly more with higher N*r rather than with higher t.) + * t = 2 increases the time by another 20% and decreases the normalized + * area-time to 89% of optimal. Thus, these two values are reasonable to use + * for fine-tuning. Values of t higher than 2 result in further increase in + * time while reducing the efficiency much further (e.g., down to around 50% of + * optimal for t = 5, which runs 3 to 4 times slower than t = 0, with exact + * numbers varying by the flags settings). + * + * Classic scrypt is available by setting t = 0 and flags to YESCRYPT_WORM and + * passing a dummy shared structure (see the description of + * yescrypt_init_shared() above for how to produce one). In this mode, the + * thread-local memory region (RAM) is first sequentially written to and then + * randomly read from. This algorithm is friendly towards time-memory + * tradeoffs (TMTO), available both to defenders (albeit not in this + * implementation) and to attackers. + * + * Setting YESCRYPT_RW adds extra random reads and writes to the thread-local + * memory region (RAM), which makes TMTO a lot less efficient. This may be + * used to slow down the kinds of attackers who would otherwise benefit from + * classic scrypt's efficient TMTO. Since classic scrypt's TMTO allows not + * only for the tradeoff, but also for a decrease of attacker's area-time (by + * up to a constant factor), setting YESCRYPT_RW substantially increases the + * cost of attacks in area-time terms as well. Yet another benefit of it is + * that optimal area-time is reached at an earlier time than with classic + * scrypt, and t = 0 actually corresponds to this earlier completion time, + * resulting in quicker hash computations (and thus in higher request rate + * capacity). Due to these properties, YESCRYPT_RW should almost always be + * set, except when compatibility with classic scrypt or TMTO-friendliness are + * desired. + * + * YESCRYPT_PARALLEL_SMIX moves parallelism that is present with p > 1 to a + * lower level as compared to where it is in classic scrypt. This reduces + * flexibility for efficient computation (for both attackers and defenders) by + * requiring that, short of resorting to TMTO, the full amount of memory be + * allocated as needed for the specified p, regardless of whether that + * parallelism is actually being fully made use of or not. (For comparison, a + * single instance of classic scrypt may be computed in less memory without any + * CPU time overhead, but in more real time, by not making full use of the + * parallelism.) This may be desirable when the defender has enough memory + * with sufficiently low latency and high bandwidth for efficient full parallel + * execution, yet the required memory size is high enough that some likely + * attackers might end up being forced to choose between using higher latency + * memory than they could use otherwise (waiting for data longer) or using TMTO + * (waiting for data more times per one hash computation). The area-time cost + * for other kinds of attackers (who would use the same memory type and TMTO + * factor or no TMTO either way) remains roughly the same, given the same + * running time for the defender. In the TMTO-friendly YESCRYPT_WORM mode, as + * long as the defender has enough memory that is just as fast as the smaller + * per-thread regions would be, doesn't expect to ever need greater + * flexibility (except possibly via TMTO), and doesn't need backwards + * compatibility with classic scrypt, there are no other serious drawbacks to + * this setting. In the YESCRYPT_RW mode, which is meant to discourage TMTO, + * this new approach to parallelization makes TMTO less inefficient. (This is + * an unfortunate side-effect of avoiding some random writes, as we have to in + * order to allow for parallel threads to access a common memory region without + * synchronization overhead.) Thus, in this mode this setting poses an extra + * tradeoff of its own (higher area-time cost for a subset of attackers vs. + * better TMTO resistance). Setting YESCRYPT_PARALLEL_SMIX also changes the + * way the running time is to be controlled from N*r*p (for classic scrypt) to + * N*r (in this modification). All of this applies only when p > 1. For + * p = 1, this setting is a no-op. + * + * Passing a real shared structure, with ROM contents previously computed by + * yescrypt_init_shared(), enables the use of ROM and requires YESCRYPT_RW for + * the thread-local RAM region. In order to allow for initialization of the + * ROM to be split into a separate program, the shared->shared1.aligned and + * shared->shared1.aligned_size fields may be set by the caller of + * yescrypt_kdf() manually rather than with yescrypt_init_shared(). + * + * local must be initialized with yescrypt_init_local(). + * + * MT-safe as long as local and buf are local to the thread. + */ +extern int yescrypt_kdf(const yescrypt_shared_t * __shared, + yescrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, uint32_t __t, + yescrypt_flags_t __flags, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt_r(shared, local, passwd, passwdlen, setting, buf, buflen): + * Compute and encode an scrypt or enhanced scrypt hash of passwd given the + * parameters and salt value encoded in setting. If the shared structure is + * not dummy, a ROM is used and YESCRYPT_RW is required. Otherwise, whether to + * use the YESCRYPT_WORM (classic scrypt) or YESCRYPT_RW (time-memory tradeoff + * discouraging modification) is determined by the setting string. shared and + * local must be initialized as described above for yescrypt_kdf(). buf must + * be large enough (as indicated by buflen) to hold the encoded hash string. + * + * Return the encoded hash string on success; or NULL on error. + * + * MT-safe as long as local and buf are local to the thread. + */ +extern uint8_t * yescrypt_r(const yescrypt_shared_t * __shared, + yescrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __setting, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt(passwd, setting): + * Compute and encode an scrypt or enhanced scrypt hash of passwd given the + * parameters and salt value encoded in setting. Whether to use the + * YESCRYPT_WORM (classic scrypt) or YESCRYPT_RW (time-memory tradeoff + * discouraging modification) is determined by the setting string. + * + * Return the encoded hash string on success; or NULL on error. + * + * This is a crypt(3)-like interface, which is simpler to use than + * yescrypt_r(), but it is not MT-safe, it does not allow for the use of a ROM, + * and it is slower than yescrypt_r() for repeated calls because it allocates + * and frees memory on each call. + * + * MT-unsafe. + */ +extern uint8_t * yescrypt(const uint8_t * __passwd, const uint8_t * __setting); + +/** + * yescrypt_gensalt_r(N_log2, r, p, flags, src, srclen, buf, buflen): + * Generate a setting string for use with yescrypt_r() and yescrypt() by + * encoding into it the parameters N_log2 (which is to be set to base 2 + * logarithm of the desired value for N), r, p, flags, and a salt given by src + * (of srclen bytes). buf must be large enough (as indicated by buflen) to + * hold the setting string. + * + * Return the setting string on success; or NULL on error. + * + * MT-safe as long as buf is local to the thread. + */ +extern uint8_t * yescrypt_gensalt_r( + uint32_t __N_log2, uint32_t __r, uint32_t __p, + yescrypt_flags_t __flags, + const uint8_t * __src, size_t __srclen, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt_gensalt(N_log2, r, p, flags, src, srclen): + * Generate a setting string for use with yescrypt_r() and yescrypt(). This + * function is the same as yescrypt_gensalt_r() except that it uses a static + * buffer and thus is not MT-safe. + * + * Return the setting string on success; or NULL on error. + * + * MT-unsafe. + */ +extern uint8_t * yescrypt_gensalt( + uint32_t __N_log2, uint32_t __r, uint32_t __p, + yescrypt_flags_t __flags, + const uint8_t * __src, size_t __srclen); + +extern char *yescrypt_client_key; +extern int yescrypt_client_key_len; + +#ifdef __cplusplus +} +#endif + +#endif