diff options
28 files changed, 325 insertions, 163 deletions
diff --git a/.travis.yml b/.travis.yml index 07b92aaff..516e4f8e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ before_script: - if [ -n "$OSX_SDK" -a -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C contrib/depends/SDKs -xf contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-g++ \$(which $HOST-g++-posix)"; fi - if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-gcc \$(which $HOST-gcc-posix)"; fi - - if [ -z "$NO_DEPENDS" ]; then $DOCKER_EXEC bash -c "CONFIG_SHELL= make $MAKEJOBS -C contrib/depends HOST=$HOST $DEP_OPTS"; fi + - if [ -z "$NO_DEPENDS" ]; then $DOCKER_EXEC bash -c "make $MAKEJOBS -C contrib/depends HOST=$HOST $DEP_OPTS"; fi script: - git submodule init && git submodule update - export TRAVIS_COMMIT_LOG=`git log --format=fuller -1` diff --git a/Dockerfile b/Dockerfile index 999290c95..a6fab3823 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,9 +29,9 @@ ENV CFLAGS='-fPIC' ENV CXXFLAGS='-fPIC' #Cmake -ARG CMAKE_VERSION=3.14.0 +ARG CMAKE_VERSION=3.14.6 ARG CMAKE_VERSION_DOT=v3.14 -ARG CMAKE_HASH=aa76ba67b3c2af1946701f847073f4652af5cbd9f141f221c97af99127e75502 +ARG CMAKE_HASH=4e8ea11cabe459308671b476469eace1622e770317a15951d7b55a82ccaaccb9 RUN set -ex \ && curl -s -O https://cmake.org/files/${CMAKE_VERSION_DOT}/cmake-${CMAKE_VERSION}.tar.gz \ && echo "${CMAKE_HASH} cmake-${CMAKE_VERSION}.tar.gz" | sha256sum -c \ @@ -42,9 +42,9 @@ RUN set -ex \ && make install ## Boost -ARG BOOST_VERSION=1_69_0 -ARG BOOST_VERSION_DOT=1.69.0 -ARG BOOST_HASH=8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406 +ARG BOOST_VERSION=1_70_0 +ARG BOOST_VERSION_DOT=1.70.0 +ARG BOOST_HASH=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 RUN set -ex \ && curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \ && echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \ @@ -69,8 +69,8 @@ RUN set -ex \ ENV OPENSSL_ROOT_DIR=/usr/local/openssl-${OPENSSL_VERSION} # ZMQ -ARG ZMQ_VERSION=v4.3.1 -ARG ZMQ_HASH=2cb1240db64ce1ea299e00474c646a2453a8435b +ARG ZMQ_VERSION=v4.3.2 +ARG ZMQ_HASH=a84ffa12b2eb3569ced199660bac5ad128bff1f0 RUN set -ex \ && git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} \ && cd libzmq \ @@ -82,8 +82,8 @@ RUN set -ex \ && ldconfig # zmq.hpp -ARG CPPZMQ_VERSION=v4.3.0 -ARG CPPZMQ_HASH=213da0b04ae3b4d846c9abc46bab87f86bfb9cf4 +ARG CPPZMQ_VERSION=v4.4.1 +ARG CPPZMQ_HASH=f5b36e563598d48fcc0d82e589d3596afef945ae RUN set -ex \ && git clone https://github.com/zeromq/cppzmq.git -b ${CPPZMQ_VERSION} \ && cd cppzmq \ @@ -103,8 +103,8 @@ RUN set -ex \ && make install # Sodium -ARG SODIUM_VERSION=1.0.17 -ARG SODIUM_HASH=b732443c442239c2e0184820e9b23cca0de0828c +ARG SODIUM_VERSION=1.0.18 +ARG SODIUM_HASH=4f5e89fa84ce1d178a6765b8b46f2b6f91216677 RUN set -ex \ && git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} \ && cd libsodium \ @@ -116,8 +116,8 @@ RUN set -ex \ && make install # Udev -ARG UDEV_VERSION=v3.2.7 -ARG UDEV_HASH=4758e346a14126fc3a964de5831e411c27ebe487 +ARG UDEV_VERSION=v3.2.8 +ARG UDEV_HASH=d69f3f28348123ab7fa0ebac63ec2fd16800c5e0 RUN set -ex \ && git clone https://github.com/gentoo/eudev -b ${UDEV_VERSION} \ && cd eudev \ @@ -152,8 +152,8 @@ RUN set -ex \ && make install # Protobuf -ARG PROTOBUF_VERSION=v3.7.0 -ARG PROTOBUF_HASH=582743bf40c5d3639a70f98f183914a2c0cd0680 +ARG PROTOBUF_VERSION=v3.7.1 +ARG PROTOBUF_HASH=6973c3a5041636c1d8dc5f7f6c8c1f3c15bc63d6 RUN set -ex \ && git clone https://github.com/protocolbuffers/protobuf -b ${PROTOBUF_VERSION} \ && cd protobuf \ diff --git a/cmake/GenVersion.cmake b/cmake/GenVersion.cmake index b2ccfbc34..992539507 100644 --- a/cmake/GenVersion.cmake +++ b/cmake/GenVersion.cmake @@ -36,6 +36,7 @@ if(RET) message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.") set(VERSIONTAG "unknown") + set(VERSION_IS_RELEASE "false") configure_file("src/version.cpp.in" "${TO}") else() string(SUBSTRING ${COMMIT} 0 9 COMMIT) @@ -47,6 +48,7 @@ else() if(NOT TAGGEDCOMMIT) message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") set(VERSIONTAG "${COMMIT}") + set(VERSION_IS_RELEASE "false") else() message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") @@ -54,9 +56,11 @@ else() if(COMMIT STREQUAL TAGGEDCOMMIT) message(STATUS "You are building a tagged release") set(VERSIONTAG "release") + set(VERSION_IS_RELEASE "true") else() message(STATUS "You are ahead of or behind a tagged release") set(VERSIONTAG "${COMMIT}") + set(VERSION_IS_RELEASE "false") endif() endif() diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index d4b2a22bc..0ec992de9 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -88,13 +88,24 @@ namespace crypto { return &reinterpret_cast<const unsigned char &>(scalar); } - void generate_random_bytes_thread_safe(size_t N, uint8_t *bytes) + boost::mutex &get_random_lock() { static boost::mutex random_lock; - boost::lock_guard<boost::mutex> lock(random_lock); + return random_lock; + } + + void generate_random_bytes_thread_safe(size_t N, uint8_t *bytes) + { + boost::lock_guard<boost::mutex> lock(get_random_lock()); generate_random_bytes_not_thread_safe(N, bytes); } + void add_extra_entropy_thread_safe(const void *ptr, size_t bytes) + { + boost::lock_guard<boost::mutex> lock(get_random_lock()); + add_extra_entropy_not_thread_safe(ptr, bytes); + } + static inline bool less32(const unsigned char *k0, const unsigned char *k1) { for (int n = 31; n >= 0; --n) diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index bac456f60..8ce321f71 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -147,6 +147,7 @@ namespace crypto { }; void generate_random_bytes_thread_safe(size_t N, uint8_t *bytes); + void add_extra_entropy_thread_safe(const void *ptr, size_t bytes); /* Generate N random bytes */ diff --git a/src/crypto/random.c b/src/crypto/random.c index 74b202661..766b5f558 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -146,3 +146,18 @@ void generate_random_bytes_not_thread_safe(size_t n, void *result) { } } } + +void add_extra_entropy_not_thread_safe(const void *ptr, size_t bytes) +{ + size_t i; + + while (bytes > 0) + { + hash_permutation(&state); + const size_t round_bytes = bytes > HASH_DATA_AREA ? HASH_DATA_AREA : bytes; + for (i = 0; i < round_bytes; ++i) + state.b[i] ^= ((const uint8_t*)ptr)[i]; + bytes -= round_bytes; + ptr = cpadd(ptr, round_bytes); + } +} diff --git a/src/crypto/random.h b/src/crypto/random.h index ccb9f4853..21a66d776 100644 --- a/src/crypto/random.h +++ b/src/crypto/random.h @@ -33,3 +33,4 @@ #include <stddef.h> void generate_random_bytes_not_thread_safe(size_t n, void *result); +void add_extra_entropy_not_thread_safe(const void *ptr, size_t bytes); diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index eba633da8..2d91b881b 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -320,7 +320,9 @@ namespace hw { bool device_ledger::reset() { reset_buffer(); int offset = set_command_header_noopt(INS_RESET); - memmove(this->buffer_send+offset, MONERO_VERSION, strlen(MONERO_VERSION)); + const size_t verlen = strlen(MONERO_VERSION); + ASSERT_X(offset + verlen <= BUFFER_SEND_SIZE, "MONERO_VERSION is too long") + memmove(this->buffer_send+offset, MONERO_VERSION, verlen); offset += strlen(MONERO_VERSION); this->buffer_send[4] = offset-5; this->length_send = offset; diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index fe9028733..986087128 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -76,7 +76,7 @@ namespace hw { rct::key AKout; ABPkeys(const rct::key& A, const rct::key& B, const bool is_subaddr, bool is_subaddress, bool is_change_address, size_t index, const rct::key& P,const rct::key& AK); ABPkeys(const ABPkeys& keys) ; - ABPkeys() {index=0;is_subaddress=false;is_subaddress=false;is_change_address=false;} + ABPkeys() {index=0;is_subaddress=false;is_change_address=false;additional_key=false;} ABPkeys &operator=(const ABPkeys &keys); }; diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc index 6270d4d14..ff6fee95c 100644 --- a/src/ringct/bulletproofs.cc +++ b/src/ringct/bulletproofs.cc @@ -101,7 +101,10 @@ static rct::key get_exponent(const rct::key &base, size_t idx) { static const std::string salt("bulletproof"); std::string hashed = std::string((const char*)base.bytes, sizeof(base)) + salt + tools::get_varint_data(idx); - const rct::key e = rct::hashToPoint(rct::hash2rct(crypto::cn_fast_hash(hashed.data(), hashed.size()))); + rct::key e; + ge_p3 e_p3; + rct::hash_to_p3(e_p3, rct::hash2rct(crypto::cn_fast_hash(hashed.data(), hashed.size()))); + ge_p3_tobytes(e.bytes, &e_p3); CHECK_AND_ASSERT_THROW_MES(!(e == rct::identity()), "Exponent is point at infinity"); return e; } diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp index b5499262f..6e4d063df 100644 --- a/src/ringct/rctOps.cpp +++ b/src/ringct/rctOps.cpp @@ -620,44 +620,16 @@ namespace rct { sc_reduce32(rv.bytes); return rv; } - - key hashToPointSimple(const key & hh) { - key pointk; - ge_p1p1 point2; - ge_p2 point; - ge_p3 res; - key h = cn_fast_hash(hh); - CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&res, h.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__)); - ge_p3_to_p2(&point, &res); - ge_mul8(&point2, &point); - ge_p1p1_to_p3(&res, &point2); - ge_p3_tobytes(pointk.bytes, &res); - return pointk; - } - key hashToPoint(const key & hh) { - key pointk; - ge_p2 point; - ge_p1p1 point2; - ge_p3 res; - key h = cn_fast_hash(hh); - ge_fromfe_frombytes_vartime(&point, h.bytes); - ge_mul8(&point2, &point); - ge_p1p1_to_p3(&res, &point2); - ge_p3_tobytes(pointk.bytes, &res); - return pointk; - } - - void hashToPoint(key & pointk, const key & hh) { - ge_p2 point; - ge_p1p1 point2; - ge_p3 res; - key h = cn_fast_hash(hh); - ge_fromfe_frombytes_vartime(&point, h.bytes); - ge_mul8(&point2, &point); - ge_p1p1_to_p3(&res, &point2); - ge_p3_tobytes(pointk.bytes, &res); - } + // Hash a key to p3 representation + void hash_to_p3(ge_p3 &hash8_p3, const key &k) { + key hash_key = cn_fast_hash(k); + ge_p2 hash_p2; + ge_fromfe_frombytes_vartime(&hash_p2, hash_key.bytes); + ge_p1p1 hash8_p1p1; + ge_mul8(&hash8_p1p1, &hash_p2); + ge_p1p1_to_p3(&hash8_p3, &hash8_p1p1); + } //sums a vector of curve points (for scalars use sc_add) void sumKeys(key & Csum, const keyV & Cis) { diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index dd6d87593..c24d48e9a 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -172,10 +172,7 @@ namespace rct { key cn_fast_hash(const key64 keys); key hash_to_scalar(const key64 keys); - //returns hashToPoint as described in https://github.com/ShenNoether/ge_fromfe_writeup - key hashToPointSimple(const key &in); - key hashToPoint(const key &in); - void hashToPoint(key &out, const key &in); + void hash_to_p3(ge_p3 &hash8_p3, const key &k); //sums a vector of curve points (for scalars use sc_add) void sumKeys(key & Csum, const key &Cis); diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index ff2a81d43..a7b265d63 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -163,14 +163,11 @@ namespace rct { return verifyBorromean(bb, P1_p3, P2_p3); } - //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) - //This is a just slghtly more efficient version than the ones described below - //(will be explained in more detail in Ring Multisig paper - //These are aka MG signatutes in earlier drafts of the ring ct paper - // c.f. https://eprint.iacr.org/2015/1098 section 2. - // Gen creates a signature which proves that for some column in the keymatrix "pk" - // the signer knows a secret key for each row in that column - // Ver verifies that the MG sig was created correctly + // MLSAG signatures + // See paper by Noether (https://eprint.iacr.org/2015/1098) + // This generalization allows for some dimensions not to require linkability; + // this is used in practice for commitment data within signatures + // Note that using more than one linkable dimension is not recommended. mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) { mgSig rv; size_t cols = pk.size(); @@ -188,6 +185,7 @@ namespace rct { size_t i = 0, j = 0, ii = 0; key c, c_old, L, R, Hi; + ge_p3 Hi_p3; sc_0(c_old.bytes); vector<geDsmp> Ip(dsRows); rv.II = keyV(dsRows); @@ -208,7 +206,8 @@ namespace rct { rv.II[i] = kLRki->ki; } else { - Hi = hashToPoint(pk[index][i]); + hash_to_p3(Hi_p3, pk[index][i]); + ge_p3_tobytes(Hi.bytes, &Hi_p3); hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]); toHash[3 * i + 2] = aG[i]; toHash[3 * i + 3] = aHP[i]; @@ -235,7 +234,8 @@ namespace rct { sc_0(c.bytes); for (j = 0; j < dsRows; j++) { addKeys2(L, rv.ss[i][j], c_old, pk[i][j]); - hashToPoint(Hi, pk[i][j]); + hash_to_p3(Hi_p3, pk[i][j]); + ge_p3_tobytes(Hi.bytes, &Hi_p3); addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k); toHash[3 * j + 1] = pk[i][j]; toHash[3 * j + 2] = L; @@ -260,43 +260,42 @@ namespace rct { return rv; } - //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) - //This is a just slghtly more efficient version than the ones described below - //(will be explained in more detail in Ring Multisig paper - //These are aka MG signatutes in earlier drafts of the ring ct paper - // c.f. https://eprint.iacr.org/2015/1098 section 2. - // Gen creates a signature which proves that for some column in the keymatrix "pk" - // the signer knows a secret key for each row in that column - // Ver verifies that the MG sig was created correctly + // MLSAG signatures + // See paper by Noether (https://eprint.iacr.org/2015/1098) + // This generalization allows for some dimensions not to require linkability; + // this is used in practice for commitment data within signatures + // Note that using more than one linkable dimension is not recommended. bool MLSAG_Ver(const key &message, const keyM & pk, const mgSig & rv, size_t dsRows) { - size_t cols = pk.size(); - CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!"); + CHECK_AND_ASSERT_MES(cols >= 2, false, "Signature must contain more than one public key"); size_t rows = pk[0].size(); - CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pk"); + CHECK_AND_ASSERT_MES(rows >= 1, false, "Bad total row number"); for (size_t i = 1; i < cols; ++i) { - CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular"); + CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "Bad public key matrix dimensions"); } - CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Bad II size"); - CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size"); + CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Wrong number of key images present"); + CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad scalar matrix dimensions"); for (size_t i = 0; i < cols; ++i) { - CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular"); + CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "Bad scalar matrix dimensions"); } - CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Bad dsRows value"); + CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Non-double-spend rows cannot exceed total rows"); - for (size_t i = 0; i < rv.ss.size(); ++i) - for (size_t j = 0; j < rv.ss[i].size(); ++j) - CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad ss slot"); - CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad cc"); + for (size_t i = 0; i < rv.ss.size(); ++i) { + for (size_t j = 0; j < rv.ss[i].size(); ++j) { + CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad signature scalar"); + } + } + CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad initial signature hash"); size_t i = 0, j = 0, ii = 0; - key c, L, R, Hi; + key c, L, R; key c_old = copy(rv.cc); vector<geDsmp> Ip(dsRows); for (i = 0 ; i < dsRows ; i++) { + CHECK_AND_ASSERT_MES(!(rv.II[i] == rct::identity()), false, "Bad key image"); precomp(Ip[i].k, rv.II[i]); } - size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper + size_t ndsRows = 3 * dsRows; // number of dimensions not requiring linkability keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows)); toHash[0] = message; i = 0; @@ -304,9 +303,14 @@ namespace rct { sc_0(c.bytes); for (j = 0; j < dsRows; j++) { addKeys2(L, rv.ss[i][j], c_old, pk[i][j]); - hashToPoint(Hi, pk[i][j]); - CHECK_AND_ASSERT_MES(!(Hi == rct::identity()), false, "Data hashed to point at infinity"); - addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k); + + // Compute R directly + ge_p3 hash8_p3; + hash_to_p3(hash8_p3, pk[i][j]); + ge_p2 R_p2; + ge_double_scalarmult_precomp_vartime(&R_p2, rv.ss[i][j].bytes, &hash8_p3, c_old.bytes, Ip[j].k); + ge_tobytes(R.bytes, &R_p2); + toHash[3 * j + 1] = pk[i][j]; toHash[3 * j + 2] = L; toHash[3 * j + 3] = R; @@ -317,6 +321,7 @@ namespace rct { toHash[ndsRows + 2 * ii + 2] = L; } c = hash_to_scalar(toHash); + CHECK_AND_ASSERT_MES(!(c == rct::zero()), false, "Bad signature hash"); copy(c_old, c); i = (i + 1); } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 73138686d..1fc4b816f 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -2147,6 +2147,7 @@ namespace cryptonote return r; res.version = CORE_RPC_VERSION; + res.release = MONERO_VERSION_IS_RELEASE; res.status = CORE_RPC_STATUS_OK; return true; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index aed967efb..325ac4343 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -87,7 +87,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 2 -#define CORE_RPC_VERSION_MINOR 9 +#define CORE_RPC_VERSION_MINOR 10 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -2053,11 +2053,13 @@ namespace cryptonote { std::string status; uint32_t version; + bool release; bool untrusted; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(status) KV_SERIALIZE(version) + KV_SERIALIZE(release) KV_SERIALIZE(untrusted) END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 5d7321e48..9c3dc2b32 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1254,7 +1254,7 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, b } else { - bool r = epee::file_io_utils::save_string_to_file(filename, ciphertext); + bool r = m_wallet->save_to_file(filename, ciphertext); if (!r) { fail_msg_writer() << tr("failed to save file ") << filename; @@ -1315,7 +1315,7 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, b { const std::string &filename = args[n]; std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); + bool r = m_wallet->load_from_file(filename, data); if (!r) { fail_msg_writer() << tr("failed to read file ") << filename; @@ -1626,7 +1626,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) if (!filenames.empty()) filenames += ", "; filenames += filename; - if (!epee::file_io_utils::save_string_to_file(filename, cryptonote::tx_to_blob(ptx.tx))) + if (!m_wallet->save_to_file(filename, cryptonote::tx_to_blob(ptx.tx))) { fail_msg_writer() << tr("Failed to export multisig transaction to file ") << filename; return true; @@ -2712,6 +2712,35 @@ bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std return true; } +bool simple_wallet::set_export_format(const std::vector<std::string> &args/* = std::vector<std::string()*/) +{ + if (args.size() < 2) + { + fail_msg_writer() << tr("Export format not specified"); + return true; + } + + if (boost::algorithm::iequals(args[1], "ascii")) + { + m_wallet->set_export_format(tools::wallet2::ExportFormat::Ascii); + } + else if (boost::algorithm::iequals(args[1], "binary")) + { + m_wallet->set_export_format(tools::wallet2::ExportFormat::Binary); + } + else + { + fail_msg_writer() << tr("Export format not recognized."); + return true; + } + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + } + return true; +} + bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { if(args.empty()) @@ -2912,7 +2941,9 @@ simple_wallet::simple_wallet() "setup-background-mining <1|0>\n " " Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n " "device-name <device_name[:device_spec]>\n " - " Device name for hardware wallet.")); + " Device name for hardware wallet.\n " + "export-format <\"binary\"|\"ascii\">\n " + " Save all exported files as binary (cannot be copied and pasted) or ascii (can be).\n ")); m_cmd_binder.set_handler("encrypted_seed", boost::bind(&simple_wallet::encrypted_seed, this, _1), tr("Display the encrypted Electrum-style mnemonic seed.")); @@ -3278,6 +3309,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) success_msg_writer() << "track-uses = " << m_wallet->track_uses(); success_msg_writer() << "setup-background-mining = " << setup_background_mining_string; success_msg_writer() << "device-name = " << m_wallet->device_name(); + success_msg_writer() << "export-format = " << (m_wallet->export_format() == tools::wallet2::ExportFormat::Ascii ? "ascii" : "binary"); return true; } else @@ -3336,6 +3368,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no")); CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>")); + CHECK_SIMPLE_VARIABLE("export-format", set_export_format, tr("\"binary\" or \"ascii\"")); } fail_msg_writer() << tr("set: unrecognized argument(s)"); return true; @@ -7312,7 +7345,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args) { std::string sig_str = m_wallet->get_tx_proof(txid, info.address, info.is_subaddress, args.size() == 3 ? args[2] : ""); const std::string filename = "monero_tx_proof"; - if (epee::file_io_utils::save_string_to_file(filename, sig_str)) + if (m_wallet->save_to_file(filename, sig_str, true)) success_msg_writer() << tr("signature file saved to: ") << filename; else fail_msg_writer() << tr("failed to save signature file"); @@ -7440,7 +7473,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args) // read signature file std::string sig_str; - if (!epee::file_io_utils::load_file_to_string(args[2], sig_str)) + if (!m_wallet->load_from_file(args[2], sig_str)) { fail_msg_writer() << tr("failed to load signature file"); return true; @@ -7524,7 +7557,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args) { const std::string sig_str = m_wallet->get_spend_proof(txid, args.size() == 2 ? args[1] : ""); const std::string filename = "monero_spend_proof"; - if (epee::file_io_utils::save_string_to_file(filename, sig_str)) + if (m_wallet->save_to_file(filename, sig_str, true)) success_msg_writer() << tr("signature file saved to: ") << filename; else fail_msg_writer() << tr("failed to save signature file"); @@ -7554,7 +7587,7 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args) return true; std::string sig_str; - if (!epee::file_io_utils::load_file_to_string(args[1], sig_str)) + if (!m_wallet->load_from_file(args[1], sig_str)) { fail_msg_writer() << tr("failed to load signature file"); return true; @@ -7613,7 +7646,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args) { const std::string sig_str = m_wallet->get_reserve_proof(account_minreserve, args.size() == 2 ? args[1] : ""); const std::string filename = "monero_reserve_proof"; - if (epee::file_io_utils::save_string_to_file(filename, sig_str)) + if (m_wallet->save_to_file(filename, sig_str, true)) success_msg_writer() << tr("signature file saved to: ") << filename; else fail_msg_writer() << tr("failed to save signature file"); @@ -7648,7 +7681,7 @@ bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args) } std::string sig_str; - if (!epee::file_io_utils::load_file_to_string(args[1], sig_str)) + if (!m_wallet->load_from_file(args[1], sig_str)) { fail_msg_writer() << tr("failed to load signature file"); return true; @@ -9011,7 +9044,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args) std::string filename = args[0]; std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); + bool r = m_wallet->load_from_file(filename, data); if (!r) { fail_msg_writer() << tr("failed to read file ") << filename; @@ -9037,7 +9070,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args) std::string signature= args[2]; std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); + bool r = m_wallet->load_from_file(filename, data); if (!r) { fail_msg_writer() << tr("failed to read file ") << filename; @@ -9255,7 +9288,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args_) try { std::string data = m_wallet->export_outputs_to_str(all); - bool r = epee::file_io_utils::save_string_to_file(filename, data); + bool r = m_wallet->save_to_file(filename, data); if (!r) { fail_msg_writer() << tr("failed to save file ") << filename; @@ -9288,7 +9321,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args) std::string filename = args[0]; std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); + bool r = m_wallet->load_from_file(filename, data); if (!r) { fail_msg_writer() << tr("failed to read file ") << filename; @@ -9489,7 +9522,7 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_ tx_to_blob(ptx.tx, blob); const std::string blob_hex = epee::string_tools::buff_to_hex_nodelimer(blob); const std::string filename = "raw_monero_tx" + (ptx_vector.size() == 1 ? "" : ("_" + std::to_string(i++))); - if (epee::file_io_utils::save_string_to_file(filename, blob_hex)) + if (m_wallet->save_to_file(filename, blob_hex, true)) success_msg_writer(true) << tr("Transaction successfully saved to ") << filename << tr(", txid ") << txid; else fail_msg_writer() << tr("Failed to save transaction to ") << filename << tr(", txid ") << txid; @@ -10274,7 +10307,7 @@ void simple_wallet::mms_export(const std::vector<std::string> &args) if (valid_id) { const std::string filename = "mms_message_content"; - if (epee::file_io_utils::save_string_to_file(filename, m.content)) + if (m_wallet->save_to_file(filename, m.content)) { success_msg_writer() << tr("Message content saved to: ") << filename; } diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 2de390666..cbc1cb6fa 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -146,6 +146,7 @@ namespace cryptonote bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>()); bool set_setup_background_mining(const std::vector<std::string> &args = std::vector<std::string>()); bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>()); + bool set_export_format(const std::vector<std::string> &args = std::vector<std::string>()); bool help(const std::vector<std::string> &args = std::vector<std::string>()); bool start_mining(const std::vector<std::string> &args); bool stop_mining(const std::vector<std::string> &args); diff --git a/src/version.cpp.in b/src/version.cpp.in index 28ce38df7..9121cdf85 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -2,6 +2,7 @@ #define DEF_MONERO_VERSION "0.14.1.2" #define DEF_MONERO_RELEASE_NAME "Boron Butterfly" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG +#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@ #include "version.h" @@ -9,3 +10,4 @@ const char* const MONERO_VERSION_TAG = DEF_MONERO_VERSION_TAG; const char* const MONERO_VERSION = DEF_MONERO_VERSION; const char* const MONERO_RELEASE_NAME = DEF_MONERO_RELEASE_NAME; const char* const MONERO_VERSION_FULL = DEF_MONERO_VERSION_FULL; +const bool MONERO_VERSION_IS_RELEASE = DEF_MONERO_VERSION_IS_RELEASE; diff --git a/src/version.h b/src/version.h index d1d06c790..b740d3360 100644 --- a/src/version.h +++ b/src/version.h @@ -4,3 +4,4 @@ extern const char* const MONERO_VERSION_TAG; extern const char* const MONERO_VERSION; extern const char* const MONERO_RELEASE_NAME; extern const char* const MONERO_VERSION_FULL; +extern const bool MONERO_VERSION_IS_RELEASE; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 9782e4b1e..155f44129 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -40,6 +40,7 @@ #include <boost/asio/ip/address.hpp> #include <boost/range/adaptor/transformed.hpp> #include <boost/preprocessor/stringize.hpp> +#include <openssl/evp.h> #include "include_base_utils.h" using namespace epee; @@ -138,6 +139,8 @@ using namespace cryptonote; static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1"; static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1"; +static const std::string ASCII_OUTPUT_MAGIC = "MoneroAsciiDataV1"; + namespace { std::string get_default_ringdb_path() @@ -275,6 +278,7 @@ struct options { const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" }; const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false}; const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false}; + const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, wihch typically means more than 256 bits of data)")}; }; void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file) @@ -476,6 +480,15 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl if (command_line::get_arg(vm, opts.offline)) wallet->set_offline(); + const std::string extra_entropy = command_line::get_arg(vm, opts.extra_entropy); + if (!extra_entropy.empty()) + { + std::string data; + THROW_WALLET_EXCEPTION_IF(!epee::file_io_utils::load_file_to_string(extra_entropy, data), + tools::error::wallet_internal_error, "Failed to load extra entropy from " + extra_entropy); + add_extra_entropy_thread_safe(data.data(), data.size()); + } + try { if (!command_line::is_arg_defaulted(vm, opts.tx_notify)) @@ -1143,7 +1156,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended): m_device_last_key_image_sync(0), m_use_dns(true), m_offline(false), - m_rpc_version(0) + m_rpc_version(0), + m_export_format(ExportFormat::Binary) { } @@ -1200,6 +1214,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.tx_notify); command_line::add_arg(desc_params, opts.no_dns); command_line::add_arg(desc_params, opts.offline); + command_line::add_arg(desc_params, opts.extra_entropy); } std::pair<std::unique_ptr<wallet2>, tools::password_container> wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) @@ -3647,6 +3662,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetInt(m_original_keys_available ? 1 : 0); json.AddMember("original_keys_available", value2, json.GetAllocator()); + value2.SetInt(m_export_format); + json.AddMember("export_format", value2, json.GetAllocator()); + value2.SetUint(1); json.AddMember("encrypted_secret_keys", value2, json.GetAllocator()); @@ -3684,7 +3702,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable std::string tmp_file_name = keys_file_name + ".new"; std::string buf; r = ::serialization::dump_binary(keys_file_data, buf); - r = r && epee::file_io_utils::save_string_to_file(tmp_file_name, buf); + r = r && save_to_file(tmp_file_name, buf); CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name); unlock_keys_file(); @@ -3741,7 +3759,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ wallet2::keys_file_data keys_file_data; std::string buf; bool encrypted_secret_keys = false; - bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf); + bool r = load_from_file(keys_file_name, buf); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name); // Decrypt the contents @@ -3754,7 +3772,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject()) crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); - // The contents should be JSON if the wallet follows the new format. if (json.Parse(account_data.c_str()).HasParseError()) { @@ -3793,6 +3810,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR; m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_original_keys_available = false; + m_export_format = ExportFormat::Binary; m_device_name = ""; m_device_derivation_path = ""; m_key_device_type = hw::device::device_type::SOFTWARE; @@ -3954,6 +3972,9 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false); encrypted_secret_keys = field_encrypted_secret_keys; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, export_format, ExportFormat, Int, false, Binary); + m_export_format = field_export_format; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_name, std::string, String, false, std::string()); if (m_device_name.empty()) { @@ -4101,7 +4122,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip wallet2::keys_file_data keys_file_data; std::string buf; bool encrypted_secret_keys = false; - bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf); + bool r = load_from_file(keys_file_name, buf); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name); // Decrypt the contents @@ -4186,7 +4207,7 @@ void wallet2::create_keys_file(const std::string &wallet_, bool watch_only, cons if (create_address_file) { - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + r = save_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype), true); if(!r) MERROR("String with address text not saved"); } } @@ -4208,7 +4229,7 @@ bool wallet2::query_device(hw::device::device_type& device_type, const std::stri rapidjson::Document json; wallet2::keys_file_data keys_file_data; std::string buf; - bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf); + bool r = load_from_file(keys_file_name, buf); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name); // Decrypt the contents @@ -4757,7 +4778,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor if (boost::filesystem::exists(m_wallet_file + ".address.txt")) { - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); + r = save_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype), true); if(!r) MERROR("String with address text not saved"); } } @@ -5266,7 +5287,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass { wallet2::cache_file_data cache_file_data; std::string buf; - bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf, std::numeric_limits<size_t>::max()); + bool r = load_from_file(m_wallet_file, buf, std::numeric_limits<size_t>::max()); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file); // try to read it as an encrypted cache @@ -5501,7 +5522,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas { // save address to the new file const std::string address_file = m_wallet_file + ".address.txt"; - r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_nettype)); + r = save_to_file(address_file, m_account.get_public_address_str(m_nettype), true); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); } // remove old wallet file @@ -5536,7 +5557,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas binary_archive<true> oar(oss); bool success = ::serialization::serialize(oar, cache_file_data); if (success) { - success = epee::file_io_utils::save_string_to_file(new_file, oss.str()); + success = save_to_file(new_file, oss.str()); } THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file); #else @@ -6164,7 +6185,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri std::string ciphertext = dump_tx_to_str(ptx_vector); if (ciphertext.empty()) return false; - return epee::file_io_utils::save_string_to_file(filename, ciphertext); + return save_to_file(filename, ciphertext); } //---------------------------------------------------------------------------------------------------- std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const @@ -6206,7 +6227,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode); return false; } - if (!epee::file_io_utils::load_file_to_string(unsigned_filename.c_str(), s)) + if (!load_from_file(unsigned_filename.c_str(), s)) { LOG_PRINT_L0("Failed to load from " << unsigned_filename); return false; @@ -6427,7 +6448,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f return false; } - if (!epee::file_io_utils::save_string_to_file(signed_filename, ciphertext)) + if (!save_to_file(signed_filename, ciphertext)) { LOG_PRINT_L0("Failed to save file to " << signed_filename); return false; @@ -6439,7 +6460,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f { std::string tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(signed_txes.ptx[i].tx)); std::string raw_filename = signed_filename + "_raw" + (signed_txes.ptx.size() == 1 ? "" : ("_" + std::to_string(i))); - if (!epee::file_io_utils::save_string_to_file(raw_filename, tx_as_hex)) + if (!save_to_file(raw_filename, tx_as_hex)) { LOG_PRINT_L0("Failed to save file to " << raw_filename); return false; @@ -6487,7 +6508,7 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal return false; } - if (!epee::file_io_utils::load_file_to_string(signed_filename.c_str(), s)) + if (!load_from_file(signed_filename.c_str(), s)) { LOG_PRINT_L0("Failed to load from " << signed_filename); return false; @@ -6618,7 +6639,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set &txs, const std::string &fi std::string ciphertext = save_multisig_tx(txs); if (ciphertext.empty()) return false; - return epee::file_io_utils::save_string_to_file(filename, ciphertext); + return save_to_file(filename, ciphertext); } //---------------------------------------------------------------------------------------------------- wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const @@ -6646,7 +6667,7 @@ bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const std::string ciphertext = save_multisig_tx(ptx_vector); if (ciphertext.empty()) return false; - return epee::file_io_utils::save_string_to_file(filename, ciphertext); + return save_to_file(filename, ciphertext); } //---------------------------------------------------------------------------------------------------- bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const @@ -6737,7 +6758,7 @@ bool wallet2::load_multisig_tx_from_file(const std::string &filename, multisig_t LOG_PRINT_L0("File " << filename << " does not exist: " << errcode); return false; } - if (!epee::file_io_utils::load_file_to_string(filename.c_str(), s)) + if (!load_from_file(filename.c_str(), s)) { LOG_PRINT_L0("Failed to load from " << filename); return false; @@ -11633,7 +11654,7 @@ bool wallet2::export_key_images(const std::string &filename, bool all) const // encrypt data, keep magic plaintext PERF_TIMER(export_key_images_encrypt); std::string ciphertext = encrypt_with_view_secret_key(data); - return epee::file_io_utils::save_string_to_file(filename, magic + ciphertext); + return save_to_file(filename, magic + ciphertext); } //---------------------------------------------------------------------------------------------------- @@ -11698,7 +11719,7 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent { PERF_TIMER(import_key_images_fsu); std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); + bool r = load_from_file(filename, data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename); @@ -13102,6 +13123,83 @@ void wallet2::throw_on_rpc_response_error(const boost::optional<std::string> &st THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, m_trusted_daemon ? *status : "daemon error"); } //---------------------------------------------------------------------------------------------------- + +bool wallet2::save_to_file(const std::string& path_to_file, const std::string& raw, bool is_printable) const +{ + if (is_printable || m_export_format == ExportFormat::Binary) + { + return epee::file_io_utils::save_string_to_file(path_to_file, raw); + } + + FILE *fp = fopen(path_to_file.c_str(), "w+"); + // Save the result b/c we need to close the fp before returning success/failure. + int write_result = PEM_write(fp, ASCII_OUTPUT_MAGIC.c_str(), "", (const unsigned char *) raw.c_str(), raw.length()); + fclose(fp); + + if (write_result == 0) + { + return false; + } + else + { + return true; + } +} +//---------------------------------------------------------------------------------------------------- + +bool wallet2::load_from_file(const std::string& path_to_file, std::string& target_str, + size_t max_size) +{ + std::string data; + bool r = epee::file_io_utils::load_file_to_string(path_to_file, data, max_size); + if (!r) + { + return false; + } + + if (!boost::algorithm::contains(boost::make_iterator_range(data.begin(), data.end()), ASCII_OUTPUT_MAGIC)) + { + // It's NOT our ascii dump. + target_str = std::move(data); + return true; + } + + // Creating a BIO and calling PEM_read_bio instead of simpler PEM_read + // to avoid reading the file from disk twice. + BIO* b = BIO_new_mem_buf((const void*) data.data(), data.length()); + + char *name = NULL; + char *header = NULL; + unsigned char *openssl_data = NULL; + long len = 0; + + // Save the result b/c we need to free the data before returning success/failure. + int success = PEM_read_bio(b, &name, &header, &openssl_data, &len); + + try + { + target_str = std::string((const char*) openssl_data, len); + } + catch (...) + { + success = 0; + } + + OPENSSL_free((void *) name); + OPENSSL_free((void *) header); + OPENSSL_free((void *) openssl_data); + BIO_free(b); + + if (success == 0) + { + return false; + } + else + { + return true; + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const { KECCAK_CTX state; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c2e34dd76..e1aca1e89 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -227,6 +227,11 @@ private: BackgroundMiningNo = 2, }; + enum ExportFormat { + Binary = 0, + Ascii, + }; + static const char* tr(const char* str); static bool has_testnet_option(const boost::program_options::variables_map& vm); @@ -1050,6 +1055,8 @@ private: void device_name(const std::string & device_name) { m_device_name = device_name; } const std::string & device_derivation_path() const { return m_device_derivation_path; } void device_derivation_path(const std::string &device_derivation_path) { m_device_derivation_path = device_derivation_path; } + const ExportFormat & export_format() const { return m_export_format; } + inline void set_export_format(const ExportFormat& export_format) { m_export_format = export_format; } bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const; void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys); @@ -1300,6 +1307,9 @@ private: bool frozen(const crypto::key_image &ki) const; bool frozen(const transfer_details &td) const; + bool save_to_file(const std::string& path_to_file, const std::string& binary, bool is_printable = false) const; + static bool load_from_file(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000); + uint64_t get_bytes_sent() const; uint64_t get_bytes_received() const; @@ -1546,6 +1556,8 @@ private: std::shared_ptr<tools::Notify> m_tx_notify; std::unique_ptr<wallet_device_callback> m_device_callback; + + ExportFormat m_export_format; }; } BOOST_CLASS_VERSION(tools::wallet2, 28) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index c64b662f3..7c87e7114 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -36,6 +36,7 @@ #include "include_base_utils.h" using namespace epee; +#include "version.h" #include "wallet_rpc_server.h" #include "wallet/wallet_args.h" #include "common/command_line.h" @@ -4188,6 +4189,7 @@ namespace tools bool wallet_rpc_server::on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx) { res.version = WALLET_RPC_VERSION; + res.release = MONERO_VERSION_IS_RELEASE; return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 4504ac752..2dfe6db85 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -47,7 +47,7 @@ // advance which version they will stop working with // Don't go over 32767 for any of these #define WALLET_RPC_VERSION_MAJOR 1 -#define WALLET_RPC_VERSION_MINOR 13 +#define WALLET_RPC_VERSION_MINOR 14 #define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR) namespace tools @@ -2418,9 +2418,11 @@ namespace wallet_rpc struct response_t { uint32_t version; + bool release; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(version) + KV_SERIALIZE(release) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index c32e0df20..bd7414c59 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -57,7 +57,6 @@ #include "rct_mlsag.h" #include "equality.h" #include "range_proof.h" -#include "rct_mlsag.h" #include "bulletproof.h" #include "crypto_ops.h" #include "multiexp.h" @@ -214,14 +213,8 @@ int main(int argc, char** argv) TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 32); TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 16384); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, true); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, true); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, true); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, true); + TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, false); + TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, true); TEST_PERFORMANCE2(filter, p, test_equality, memcmp32, true); TEST_PERFORMANCE2(filter, p, test_equality, memcmp32, false); @@ -251,15 +244,6 @@ int main(int argc, char** argv) TEST_PERFORMANCE6(filter, p, test_aggregated_bulletproof, false, 2, 1, 1, 0, 64); TEST_PERFORMANCE6(filter, p, test_aggregated_bulletproof, true, 2, 1, 1, 0, 64); // 64 proof, each with 2 amounts - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, false); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, true); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, true); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, true); - TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, true); - TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_add); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_sub); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_mul); diff --git a/tests/performance_tests/rct_mlsag.h b/tests/performance_tests/rct_mlsag.h index 0141710f7..59eae074e 100644 --- a/tests/performance_tests/rct_mlsag.h +++ b/tests/performance_tests/rct_mlsag.h @@ -35,13 +35,13 @@ #include "single_tx_test_base.h" -template<size_t inputs, size_t ring_size, bool ver> +template<size_t ring_size, bool ver> class test_ringct_mlsag : public single_tx_test_base { public: static const size_t cols = ring_size; - static const size_t rows = inputs; - static const size_t loop_count = 100; + static const size_t rows = 2; // single spend and commitment data + static const size_t loop_count = 1000; bool init() { @@ -65,7 +65,7 @@ public: { sk[j] = xm[ind][j]; } - IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default")); + IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default")); return true; } @@ -73,9 +73,9 @@ public: bool test() { if (ver) - MLSAG_Ver(rct::identity(), P, IIccss, rows); + MLSAG_Ver(rct::identity(), P, IIccss, rows-1); else - MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default")); + MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default")); return true; } diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index d2b2c3109..075aeac40 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -788,7 +788,20 @@ TEST(ringct, HPow2) { key G = scalarmultBase(d2h(1)); - key H = hashToPointSimple(G); + // Note that H is computed differently than standard hashing + // This method is not guaranteed to return a curvepoint for all inputs + // Don't use it elsewhere + key H = cn_fast_hash(G); + ge_p3 H_p3; + int decode = ge_frombytes_vartime(&H_p3, H.bytes); + ASSERT_EQ(decode, 0); // this is known to pass for the particular value G + ge_p2 H_p2; + ge_p3_to_p2(&H_p2, &H_p3); + ge_p1p1 H8_p1p1; + ge_mul8(&H8_p1p1, &H_p2); + ge_p1p1_to_p3(&H_p3, &H8_p1p1); + ge_p3_tobytes(H.bytes, &H_p3); + for (int j = 0 ; j < ATOMS ; j++) { ASSERT_TRUE(equalKeys(H, H2[j])); addKeys(H, H, H); diff --git a/utils/build_scripts/android32.Dockerfile b/utils/build_scripts/android32.Dockerfile index e49bdc652..4e4f40276 100644 --- a/utils/build_scripts/android32.Dockerfile +++ b/utils/build_scripts/android32.Dockerfile @@ -1,6 +1,6 @@ FROM debian:stable -RUN apt-get update && apt-get install -y unzip automake build-essential curl file pkg-config git python libtool +RUN apt-get update && apt-get install -y unzip automake build-essential curl file pkg-config git python libtool libtinfo5 WORKDIR /opt/android ## INSTALL ANDROID SDK diff --git a/utils/build_scripts/android64.Dockerfile b/utils/build_scripts/android64.Dockerfile index c4464fa84..90eeb4bae 100644 --- a/utils/build_scripts/android64.Dockerfile +++ b/utils/build_scripts/android64.Dockerfile @@ -1,6 +1,6 @@ FROM debian:stable -RUN apt-get update && apt-get install -y unzip automake build-essential curl file pkg-config git python libtool +RUN apt-get update && apt-get install -y unzip automake build-essential curl file pkg-config git python libtool libtinfo5 WORKDIR /opt/android ## INSTALL ANDROID SDK |