diff --git a/CMakeLists.txt b/CMakeLists.txt index ad561c2..728947d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -569,7 +569,9 @@ else() set(CMAKE_RANLIB "gcc-ranlib") endif() # Default ubuntu 16.04 LTS ld.bfd refuses to cooperate with LTO'ed ar libs for some reason, gold linker works, go figure - set(RELEASE_FLAGS "${RELEASE_FLAGS} -fuse-ld=gold") + if(NOT ARM) + set(RELEASE_FLAGS "${RELEASE_FLAGS} -fuse-ld=gold") + endif() endif() endif() diff --git a/README.md b/README.md index 97bee5c..65d6e4f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Portions Copyright (c) 2012-2013, The Cryptonote developers - Web: [www.sumokoin.org](https://www.sumokoin.org) - Mail: [contact@sumokoin.org](mailto:contact@sumokoin.org) +Please note that code is developed on the [dev branch](https://github.com/sumoprojects/sumokoin/tree/dev), if you want to check out the latest updates, before they are merged on main branch, please refer there. Master branch will always point to a version that we consider stable, so you can download the code by simply typing `git clone https://github.com/sumoprojects/sumokoin.git` + ## Introduction Sumokoin (スモコイン in Japanese) is a fork from Monero, one of the most respectable cryptocurrency well-known for **security, privacy, untraceability** and **active development**. Starting as an educational project, we found that it would be great to create a new coin with high level of privacy by (1) moving forward right away to **Ring Confidential Transactions (RingCT)**, (2) setting **minimum transaction _mixin_ to 12** that would greatly reduce chance of being attacked, traced or identified by (blockchain) statistical analysis. diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index b49dd5b..c0ea4b6 100644 Binary files a/src/blocks/checkpoints.dat and b/src/blocks/checkpoints.dat differ diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 19ee5e3..7703aea 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -40,7 +40,8 @@ set(crypto_sources skein.c tree-hash.c cn_slow_hash_soft.cpp - cn_slow_hash_hard_intel.cpp) + cn_slow_hash_hard_intel.cpp + cn_slow_hash_hard_arm.cpp) set(crypto_headers) diff --git a/src/crypto/cn_slow_hash.hpp b/src/crypto/cn_slow_hash.hpp index 55be458..f3889ad 100644 --- a/src/crypto/cn_slow_hash.hpp +++ b/src/crypto/cn_slow_hash.hpp @@ -44,7 +44,7 @@ #define HAS_WIN_INTRIN_API #endif -// Note HAS_INTEL_HW and future HAS_ARM_HW only mean we can emit the AES instructions +// Note HAS_INTEL_HW and HAS_ARM_HW only mean we can emit the AES instructions // check CPU support for the hardware AES encryption has to be done at runtime #if defined(__x86_64__) || defined(__i386__) || defined(_M_X86) || defined(_M_X64) #ifdef __GNUC__ @@ -57,6 +57,14 @@ #define HAS_INTEL_HW #endif +#if defined(__aarch64__) +#pragma GCC target ("+crypto") +#include +#include +#include +#define HAS_ARM_HW +#endif + #ifdef HAS_INTEL_HW inline void cpuid(uint32_t eax, int32_t ecx, int32_t val[4]) { @@ -83,7 +91,7 @@ inline bool hw_check_aes() #ifdef HAS_ARM_HW inline bool hw_check_aes() { - return false; + return (getauxval(AT_HWCAP) & HWCAP_AES) != 0; } #endif diff --git a/src/crypto/cn_slow_hash_hard_arm.cpp b/src/crypto/cn_slow_hash_hard_arm.cpp new file mode 100644 index 0000000..f3de0cd --- /dev/null +++ b/src/crypto/cn_slow_hash_hard_arm.cpp @@ -0,0 +1,388 @@ +// Copyright (c) 2017, SUMOKOIN +// +// 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. Neither the name of the copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// +// Parts of this file are originally copyright (c) 2014-2017, The Monero Project +// Parts of this file are originally copyright (c) 2012-2013, The Cryptonote developers + +#include "cn_slow_hash.hpp" +#include "keccak.h" + +#ifdef HAS_ARM_HW + +extern const uint8_t saes_sbox[256]; + +struct aeskeydata +{ + uint32_t x0; + uint32_t x1; + uint32_t x2; + uint32_t x3; + + aeskeydata(const uint8_t* memory) + { + const uint32_t* mem = reinterpret_cast(memory); + x0 = mem[0]; + x1 = mem[1]; + x2 = mem[2]; + x3 = mem[3]; + } + + inline uint8x16_t store() + { + uint32x4_t tmp = {x0, x1, x2, x3}; + return vreinterpretq_u8_u32(tmp); + } + + inline aeskeydata& operator^=(uint32_t rhs) noexcept + { + x0 ^= rhs; + x1 ^= rhs; + x2 ^= rhs; + x3 ^= rhs; + return *this; + } +}; + +// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1) +inline void sl_xor(aeskeydata& x) +{ + x.x1 ^= x.x0; + x.x2 ^= x.x1; + x.x3 ^= x.x2; +} + +inline uint32_t sub_word(uint32_t key) +{ + return (saes_sbox[key >> 24 ] << 24) | (saes_sbox[(key >> 16) & 0xff] << 16 ) | + (saes_sbox[(key >> 8) & 0xff] << 8 ) | saes_sbox[key & 0xff]; +} + +inline uint32_t rotr(uint32_t value, uint32_t amount) +{ + return (value >> amount) | (value << ((32 - amount) & 31)); +} + +template +inline void soft_aes_genkey_sub(aeskeydata& xout0, aeskeydata& xout2) +{ + uint32_t tmp; + sl_xor(xout0); + xout0 ^= rotr(sub_word(xout2.x3), 8) ^ rcon; + sl_xor(xout2); + xout2 ^= sub_word(xout0.x3); +} + +inline void aes_genkey(const uint8_t* memory, uint8x16_t& k0, uint8x16_t& k1, uint8x16_t& k2, uint8x16_t& k3, uint8x16_t& k4, + uint8x16_t& k5, uint8x16_t& k6, uint8x16_t& k7, uint8x16_t& k8, uint8x16_t& k9) +{ + aeskeydata xout0(memory); + aeskeydata xout2(memory + 16); + + k0 = xout0.store(); + k1 = xout2.store(); + + soft_aes_genkey_sub<0x01>(xout0, xout2); + k2 = xout0.store(); + k3 = xout2.store(); + + soft_aes_genkey_sub<0x02>(xout0, xout2); + k4 = xout0.store(); + k5 = xout2.store(); + + soft_aes_genkey_sub<0x04>(xout0, xout2); + k6 = xout0.store(); + k7 = xout2.store(); + + soft_aes_genkey_sub<0x08>(xout0, xout2); + k8 = xout0.store(); + k9 = xout2.store(); +} + +inline void aes_round10(uint8x16_t& x, const uint8x16_t& k0, const uint8x16_t& k1, const uint8x16_t& k2, const uint8x16_t& k3, + const uint8x16_t& k4, const uint8x16_t& k5, const uint8x16_t& k6, const uint8x16_t& k7, const uint8x16_t& k8, const uint8x16_t& k9) +{ + x = vaesmcq_u8(vaeseq_u8(x, vdupq_n_u8(0))); + x = vaesmcq_u8(vaeseq_u8(x, k0)); + x = vaesmcq_u8(vaeseq_u8(x, k1)); + x = vaesmcq_u8(vaeseq_u8(x, k2)); + x = vaesmcq_u8(vaeseq_u8(x, k3)); + x = vaesmcq_u8(vaeseq_u8(x, k4)); + x = vaesmcq_u8(vaeseq_u8(x, k5)); + x = vaesmcq_u8(vaeseq_u8(x, k6)); + x = vaesmcq_u8(vaeseq_u8(x, k7)); + x = vaesmcq_u8(vaeseq_u8(x, k8)); + x = veorq_u8(x, k9); +} + +inline void xor_shift(uint8x16_t& x0, uint8x16_t& x1, uint8x16_t& x2, uint8x16_t& x3, uint8x16_t& x4, uint8x16_t& x5, uint8x16_t& x6, uint8x16_t& x7) +{ + uint8x16_t tmp0 = x0; + x0 ^= x1; + x1 ^= x2; + x2 ^= x3; + x3 ^= x4; + x4 ^= x5; + x5 ^= x6; + x6 ^= x7; + x7 ^= tmp0; +} + +inline void mem_load(cn_sptr& lpad, size_t i,uint8x16_t& x0, uint8x16_t& x1, uint8x16_t& x2, uint8x16_t& x3, uint8x16_t& x4, uint8x16_t& x5, uint8x16_t& x6, uint8x16_t& x7) +{ + x0 ^= vld1q_u8(lpad.as_byte() + i); + x1 ^= vld1q_u8(lpad.as_byte() + i + 16); + x2 ^= vld1q_u8(lpad.as_byte() + i + 32); + x3 ^= vld1q_u8(lpad.as_byte() + i + 48); + x4 ^= vld1q_u8(lpad.as_byte() + i + 64); + x5 ^= vld1q_u8(lpad.as_byte() + i + 80); + x6 ^= vld1q_u8(lpad.as_byte() + i + 96); + x7 ^= vld1q_u8(lpad.as_byte() + i + 112); +} + +template +void cn_slow_hash::implode_scratchpad_hard() +{ + uint8x16_t x0, x1, x2, x3, x4, x5, x6, x7; + uint8x16_t k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; + + aes_genkey(spad.as_byte() + 32, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + x0 = vld1q_u8(spad.as_byte() + 64); + x1 = vld1q_u8(spad.as_byte() + 80); + x2 = vld1q_u8(spad.as_byte() + 96); + x3 = vld1q_u8(spad.as_byte() + 112); + x4 = vld1q_u8(spad.as_byte() + 128); + x5 = vld1q_u8(spad.as_byte() + 144); + x6 = vld1q_u8(spad.as_byte() + 160); + x7 = vld1q_u8(spad.as_byte() + 176); + + for (size_t i = 0; i < MEMORY; i += 128) + { + mem_load(lpad, i, x0, x1, x2, x3, x4, x5, x6, x7); + + aes_round10(x0, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x1, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x2, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x3, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x4, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x5, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x6, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x7, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + if(VERSION > 0) + xor_shift(x0, x1, x2, x3, x4, x5, x6, x7); + } + + for (size_t i = 0; VERSION > 0 && i < MEMORY; i += 128) + { + mem_load(lpad, i, x0, x1, x2, x3, x4, x5, x6, x7); + + aes_round10(x0, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x1, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x2, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x3, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x4, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x5, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x6, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x7, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + xor_shift(x0, x1, x2, x3, x4, x5, x6, x7); + } + + for (size_t i = 0; VERSION > 0 && i < 16; i++) + { + aes_round10(x0, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x1, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x2, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x3, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x4, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x5, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x6, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x7, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + xor_shift(x0, x1, x2, x3, x4, x5, x6, x7); + } + + vst1q_u8(spad.as_byte() + 64, x0); + vst1q_u8(spad.as_byte() + 80, x1); + vst1q_u8(spad.as_byte() + 96, x2); + vst1q_u8(spad.as_byte() + 112, x3); + vst1q_u8(spad.as_byte() + 128, x4); + vst1q_u8(spad.as_byte() + 144, x5); + vst1q_u8(spad.as_byte() + 160, x6); + vst1q_u8(spad.as_byte() + 176, x7); +} + +template +void cn_slow_hash::explode_scratchpad_hard() +{ + uint8x16_t x0, x1, x2, x3, x4, x5, x6, x7; + uint8x16_t k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; + + aes_genkey(spad.as_byte(), k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + x0 = vld1q_u8(spad.as_byte() + 64); + x1 = vld1q_u8(spad.as_byte() + 80); + x2 = vld1q_u8(spad.as_byte() + 96); + x3 = vld1q_u8(spad.as_byte() + 112); + x4 = vld1q_u8(spad.as_byte() + 128); + x5 = vld1q_u8(spad.as_byte() + 144); + x6 = vld1q_u8(spad.as_byte() + 160); + x7 = vld1q_u8(spad.as_byte() + 176); + + for (size_t i = 0; VERSION > 0 && i < 16; i++) + { + aes_round10(x0, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x1, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x2, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x3, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x4, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x5, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x6, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x7, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + xor_shift(x0, x1, x2, x3, x4, x5, x6, x7); + } + + for(size_t i = 0; i < MEMORY; i += 128) + { + aes_round10(x0, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x1, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x2, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x3, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x4, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x5, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x6, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + aes_round10(x7, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + + vst1q_u8(lpad.as_byte() + i, x0); + vst1q_u8(lpad.as_byte() + i + 16, x1); + vst1q_u8(lpad.as_byte() + i + 32, x2); + vst1q_u8(lpad.as_byte() + i + 48, x3); + vst1q_u8(lpad.as_byte() + i + 64, x4); + vst1q_u8(lpad.as_byte() + i + 80, x5); + vst1q_u8(lpad.as_byte() + i + 96, x6); + vst1q_u8(lpad.as_byte() + i + 112, x7); + } +} + +inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi) +{ + unsigned __int128 r = (unsigned __int128)a * (unsigned __int128)b; + *hi = r >> 64; + return (uint64_t)r; +} + +extern "C" void blake256_hash(uint8_t*, const uint8_t*, uint64_t); +extern "C" void groestl(const unsigned char*, unsigned long long, unsigned char*); +extern "C" size_t jh_hash(int, const unsigned char*, unsigned long long, unsigned char*); +extern "C" size_t skein_hash(int, const unsigned char*, size_t, unsigned char*); + +inline uint8x16_t _mm_set_epi64x(const uint64_t a, const uint64_t b) +{ + return vreinterpretq_u8_u64(vcombine_u64(vcreate_u64(b), vcreate_u64(a))); +} + +template +void cn_slow_hash::hardware_hash(const void* in, size_t len, void* out) +{ + keccak((const uint8_t *)in, len, spad.as_byte(), 200); + + explode_scratchpad_hard(); + + uint64_t* h0 = spad.as_uqword(); + + uint64_t al0 = h0[0] ^ h0[4]; + uint64_t ah0 = h0[1] ^ h0[5]; + uint8x16_t bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + + uint64_t idx0 = h0[0] ^ h0[4]; + + const uint8x16_t zero = vdupq_n_u8(0); + // Optim - 90% time boundary + for(size_t i = 0; i < ITER; i++) + { + uint8x16_t cx; + cx = vld1q_u8(scratchpad_ptr(idx0).as_byte()); + + cx = vaesmcq_u8(vaeseq_u8(cx, zero)) ^ _mm_set_epi64x(ah0, al0); + + vst1q_u8(scratchpad_ptr(idx0).as_byte(), bx0 ^ cx); + + idx0 = vgetq_lane_u64(vreinterpretq_u64_u8(cx), 0); + bx0 = cx; + + uint64_t hi, lo, cl, ch; + cl = scratchpad_ptr(idx0).as_uqword(0); + ch = scratchpad_ptr(idx0).as_uqword(1); + + lo = _umul128(idx0, cl, &hi); + + al0 += hi; + ah0 += lo; + scratchpad_ptr(idx0).as_uqword(0) = al0; + scratchpad_ptr(idx0).as_uqword(1) = ah0; + ah0 ^= ch; + al0 ^= cl; + idx0 = al0; + + if(VERSION > 0) + { + int64_t n = scratchpad_ptr(idx0).as_qword(0); + int32_t d = scratchpad_ptr(idx0).as_dword(2); + int64_t q = n / (d | 5); + scratchpad_ptr(idx0).as_qword(0) = n ^ q; + idx0 = d ^ q; + } + } + + implode_scratchpad_hard(); + + keccakf(spad.as_uqword(), 24); + + switch(spad.as_byte(0) & 3) + { + case 0: + blake256_hash((uint8_t*)out, spad.as_byte(), 200); + break; + case 1: + groestl(spad.as_byte(), 200 * 8, (uint8_t*)out); + break; + case 2: + jh_hash(32 * 8, spad.as_byte(), 8 * 200, (uint8_t*)out); + break; + case 3: + skein_hash(8 * 32, spad.as_byte(), 8 * 200, (uint8_t*)out); + break; + } +} + +template class cn_slow_hash<2*1024*1024, 0x80000, 0>; +template class cn_slow_hash<4*1024*1024, 0x40000, 1>; + +#endif diff --git a/src/crypto/cn_slow_hash_soft.cpp b/src/crypto/cn_slow_hash_soft.cpp index 13b6d90..ae8af9f 100644 --- a/src/crypto/cn_slow_hash_soft.cpp +++ b/src/crypto/cn_slow_hash_soft.cpp @@ -104,7 +104,7 @@ and fitness for purpose. #define saes_u3(p) saes_b2w( p, p, saes_f3(p), saes_f2(p)) alignas(16) const uint32_t saes_table[4][256] = { saes_data(saes_u0), saes_data(saes_u1), saes_data(saes_u2), saes_data(saes_u3) }; -alignas(16) const uint8_t saes_sbox[256] = saes_data(saes_h0); +alignas(16) extern const uint8_t saes_sbox[256] = saes_data(saes_h0); struct aesdata { @@ -506,6 +506,11 @@ void cn_slow_hash::software_hash(const void* in, size_t len { int64_t n = idx.as_qword(0); int32_t d = idx.as_dword(2); + +#if defined(__arm__) + asm volatile ("nop"); //Fix for RasPi3 ARM - maybe needed on armv8 +#endif + int64_t q = n / (d | 5); idx.as_qword(0) = n ^ q; idx = scratchpad_ptr(d ^ q); @@ -531,6 +536,11 @@ void cn_slow_hash::software_hash(const void* in, size_t len { int64_t n = idx.as_qword(0); // read bytes 0 - 7 int32_t d = idx.as_dword(2); // read bytes 8 - 11 + +#if defined(__arm__) + asm volatile ("nop"); //Fix for RasPi3 ARM - maybe needed on armv8 +#endif + int64_t q = n / (d | 5); idx.as_qword(0) = n ^ q; idx = scratchpad_ptr(d ^ q); diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index a38e66a..0b33739 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -166,13 +166,12 @@ namespace cryptonote ADD_CHECKPOINT(3000, "81e040955b710dc5a5056668c4eaf3fbc4da2f72c0a63763250ede32a92e0f06"); ADD_CHECKPOINT(5000, "e838c077bc66356d9bb321d4eb60f0851ef766f0619ddc4c6568a0f149aacea0"); ADD_CHECKPOINT(10000, "360b96c3d0a5202c548672d550700d982ca15ad5627f70bce0a89dda840b3611"); - ADD_CHECKPOINT(15000, "94c86b344fe2765727067997f45ca289b71ce9279ecc245c8216f94fdefb33bc"); ADD_CHECKPOINT(20000, "603a45b60dd92ef4524c80d58411d09480b4668c54bc08dd651d838832bd399e"); - ADD_CHECKPOINT(20251, "08f1086be149c18dece35b5bf0220aeb3ff8c5f01192838db8ca5a685f42d041"); + ADD_CHECKPOINT(21300, "d0a76e98ebb4d8e928d931a1807bba11a2fafdf544c119761b0ed6de4e1898cf"); // v2 fork ADD_CHECKPOINT(50000, "ae36641cf06ed788375bfb32f0038cbcd98f1d7bfb09937148fb1a57c6b52dd8"); ADD_CHECKPOINT(75000, "b26f4e1225569da282b77659020bace52e5e89abbdee33e9e52266b1e71803a5"); ADD_CHECKPOINT(100000, "ffe474fe8353f90700c8138ddea3547d5c1e4a6facb1df85897e7a6e4daab540"); - ADD_CHECKPOINT(116134, "ce0883907ab7eaa5c94fe602afc0522fa2228585789747f9f20e65dea4a465d9"); + ADD_CHECKPOINT(116520, "da1cb8f30305cd5fad7d6c33b3ed88fede053e0926102d8e544b65e93e33a08b"); // v3 fork return true; } diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index ff2936f..f803283 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -741,7 +741,7 @@ namespace cryptonote uint64_t summary_outs_money = 0; //fill outputs size_t output_index = 0; - BOOST_FOREACH(const tx_destination_entry& dst_entr, destinations) + BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts) { CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount); crypto::key_derivation derivation; @@ -762,8 +762,8 @@ namespace cryptonote if (dst_entr.addr == change_addr) { // sending change to yourself; derivation = a*R - r = crypto::generate_key_derivation(txkey.pub, sender_account_keys.m_view_secret_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey.pub << ", " << sender_account_keys.m_view_secret_key << ")"); + r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")"); } else { @@ -797,7 +797,7 @@ namespace cryptonote remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys)); - LOG_PRINT_L2("tx pubkey: " << txkey.pub); + LOG_PRINT_L2("tx pubkey: " << txkey_pub); if (need_additional_txkeys) { LOG_PRINT_L2("additional tx pubkeys: "); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c18ea05..9eb37aa 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -3452,7 +3452,7 @@ bool simple_wallet::account(const std::vector &args/* = std::vector label = tr("(Untitled account)"); m_wallet->add_subaddress_account(label); m_current_subaddress_account = m_wallet->get_num_subaddress_accounts() - 1; - //update_prompt(); + update_prompt(); LOCK_IDLE_SCOPE(); print_accounts(); } @@ -3471,7 +3471,7 @@ bool simple_wallet::account(const std::vector &args/* = std::vector return true; } m_current_subaddress_account = index_major; - //update_prompt(); + update_prompt(); show_balance(); } else if (command == "label" && local_args.size() >= 1) @@ -4164,7 +4164,8 @@ int main(int argc, char* argv[]) } cryptonote::simple_wallet w; - w.init(*vm); + if (!w.init(*vm)) + return 1; std::vector command = command_line::get_arg(*vm, arg_command); if (!command.empty()) diff --git a/src/version.h.in b/src/version.h.in index b2ceab5..281f214 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define SUMOKOIN_VERSION_TAG "@VERSIONTAG@" -#define SUMOKOIN_VERSION "0.3.0.0" +#define SUMOKOIN_VERSION "0.3.1.0" #define SUMOKOIN_RELEASE_NAME "Aomori" #define SUMOKOIN_VERSION_FULL SUMOKOIN_VERSION "-" SUMOKOIN_VERSION_TAG diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 52bbd41..84518cc 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -111,6 +111,8 @@ struct options { const command_line::arg_descriptor daemon_port = {"daemon-port", tools::wallet2::tr("Use daemon instance at port instead of 19733"), 0}; const command_line::arg_descriptor testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false}; const command_line::arg_descriptor restricted = {"restricted-rpc", tools::wallet2::tr("Restricts to view-only commands"), false}; + const command_line::arg_descriptor enable_ssl = { "enable-ssl", tools::wallet2::tr("Enable SSL for connection to daemon"), false }; + const command_line::arg_descriptor cacerts_path = { "cacerts-path", tools::wallet2::tr("Path to (SSL) CA certificates"), "" }; }; void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file) @@ -142,10 +144,17 @@ std::unique_ptr make_basic(const boost::program_options::variabl { const bool testnet = command_line::get_arg(vm, opts.testnet); const bool restricted = command_line::get_arg(vm, opts.restricted); + const bool enable_ssl = command_line::get_arg(vm, opts.enable_ssl); auto daemon_address = command_line::get_arg(vm, opts.daemon_address); auto daemon_host = command_line::get_arg(vm, opts.daemon_host); auto daemon_port = command_line::get_arg(vm, opts.daemon_port); + auto cacerts_path = command_line::get_arg(vm, opts.cacerts_path); + + if (enable_ssl) + { + LOG_PRINT_L2("SSL enabled with CA certs path: [" << (!cacerts_path.empty() ? cacerts_path : "OS default") << "]"); + } if (!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port) { @@ -165,7 +174,9 @@ std::unique_ptr make_basic(const boost::program_options::variabl daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); std::unique_ptr wallet(new tools::wallet2(testnet, restricted)); - wallet->init(daemon_address); + wallet->set_cacerts_path(cacerts_path); + wallet->init(daemon_address, 0, enable_ssl, wallet->get_cacerts_path()); + return wallet; } @@ -414,6 +425,8 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.daemon_port); command_line::add_arg(desc_params, opts.testnet); command_line::add_arg(desc_params, opts.restricted); + command_line::add_arg(desc_params, opts.enable_ssl); + command_line::add_arg(desc_params, opts.cacerts_path); } boost::optional wallet2::password_prompt(const bool new_password) @@ -514,6 +527,22 @@ void wallet2::set_seed_language(const std::string &language) { seed_language = language; } + +/*! +* \brief Gets cacerts path +*/ +const char* wallet2::get_cacerts_path() const +{ + return m_cacerts_path.empty() ? nullptr : m_cacerts_path.c_str(); +} +/*! +* \brief Sets cacerts path +* \param cacerts_path to set to +*/ +void wallet2::set_cacerts_path(const std::string &cacerts_path) +{ + m_cacerts_path = cacerts_path; +} //---------------------------------------------------------------------------------------------------- cryptonote::account_public_address wallet2::get_subaddress(const cryptonote::subaddress_index& index) const { @@ -745,7 +774,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote int threads = tools::get_max_concurrency(); const cryptonote::account_keys& keys = m_account.get_keys(); crypto::key_derivation derivation; - generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation)) + { + LOG_PRINT_L2("Failed to generate key derivation from tx pubkey, skipping"); + static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key"); + memcpy(&derivation, rct::identity().bytes, sizeof(derivation)); + } // additional tx pubkeys and derivations for multi-destination transfers involving one or more subaddresses std::vector additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx); @@ -753,7 +787,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back())){ + LOG_PRINT_L2("Failed to generate key derivation from tx pubkey, skipping"); + additional_derivations.pop_back(); + } } if (miner_tx && m_refresh_type == RefreshNoCoinbase) @@ -1236,11 +1273,11 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry ++idx; } TIME_MEASURE_FINISH(txs_handle_time); - LOG_PRINT_L2("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms"); + LOG_PRINT_L1("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms"); }else { if (!(height % 100)) - LOG_PRINT_L2( "Skipped block by timestamp, height: " << height << ", block time " << b.timestamp << ", account time " << m_account.get_createtime()); + LOG_PRINT_L1( "Skipped block by timestamp, height: " << height << ", block time " << b.timestamp << ", account time " << m_account.get_createtime()); } m_blockchain.push_back(bl_id); ++m_local_bc_height; @@ -1661,8 +1698,7 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, { std::list hashes; size_t current_index = m_blockchain.size(); - - while(m_run.load(std::memory_order_relaxed) && current_index < stop_height) + while (m_run.load(std::memory_order_relaxed) && current_index < stop_height) { pull_hashes(0, blocks_start_height, short_chain_history, hashes); if (hashes.size() < 3) @@ -1685,12 +1721,12 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, } } current_index = blocks_start_height; - BOOST_FOREACH(auto& bl_id, hashes) + for (auto& bl_id : hashes) { if(current_index >= m_blockchain.size()) { if (!(current_index % 1000)) - LOG_PRINT_L2( "Skipped block by height: " << current_index); + LOG_PRINT_L1( "Skipped block by height: " << current_index); m_blockchain.push_back(bl_id); ++m_local_bc_height; @@ -1781,13 +1817,24 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re std::list next_blocks; std::vector next_o_indices; bool error = false; + if (blocks.empty()) + { + break; + } + tpool.submit(&waiter, [&]{pull_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, next_blocks, next_o_indices, error); }); process_blocks(blocks_start_height, blocks, o_indices, added_blocks); blocks_fetched += added_blocks; waiter.wait(); + if(!added_blocks) break; + + if (blocks_start_height == next_blocks_start_height) + { + break; + } // switch to the new blocks from the daemon blocks_start_height = next_blocks_start_height; @@ -2243,14 +2290,14 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri if(m_refresh_from_block_height == 0 && !recover){ // Wallets created offline don't know blockchain height. // Set blockchain height calculated from current date/time - // -1 month for fluctuations in block time and machine date/time setup. + // -1 week for fluctuations in block time and machine date/time setup. // avg seconds per block const int seconds_per_block = DIFFICULTY_TARGET; - // ~num blocks per month - const uint64_t blocks_per_month = 60*60*24*30/seconds_per_block; + // ~num blocks per week + const uint64_t blocks_per_week = 60*60*24*7/seconds_per_block; uint64_t approx_blockchain_height = get_approximate_blockchain_height(); if(approx_blockchain_height > 0) { - m_refresh_from_block_height = approx_blockchain_height - blocks_per_month; + m_refresh_from_block_height = approx_blockchain_height - blocks_per_week; } } bool r = store_keys(m_keys_file, password, false); @@ -4980,14 +5027,17 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err) uint64_t wallet2::get_approximate_blockchain_height() const { if (m_testnet) return 0; - // time of v2 fork - const time_t fork_time = 1458748658; - // v2 fork block - const uint64_t fork_block = 1009827; + // time of v3 fork + const time_t fork_time = 1522881180; + // v3 fork block + const uint64_t fork_block = 116520; // avg seconds per block const int seconds_per_block = DIFFICULTY_TARGET; // Calculated blockchain height - uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block; + time_t current_time = time(NULL); + if (current_time <= 0) + current_time = fork_time; + uint64_t approx_blockchain_height = fork_block + (current_time - fork_time) / seconds_per_block; LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height); return approx_blockchain_height; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 61c9a96..faf6183 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -423,6 +423,15 @@ namespace tools */ void set_seed_language(const std::string &language); + /*! + * \brief Gets the cacerts path + */ + const char* get_cacerts_path() const; + /*! + * \brief Sets the cacerts path + */ + void set_cacerts_path(const std::string &cacerts_path); + // Subaddress scheme cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index& index) const; crypto::public_key get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const; @@ -726,6 +735,7 @@ namespace tools i_wallet2_callback* m_callback; bool m_testnet; bool m_restricted; + std::string m_cacerts_path; /* Path to SSL CA Cerificates*/ std::string seed_language; /*!< Language of the mnemonics (seed). */ bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ bool m_watch_only; /*!< no spend key */