Skip to content

Commit

Permalink
Merge branch 'release'
Browse files Browse the repository at this point in the history
  • Loading branch information
cryptozoidberg committed Dec 18, 2020
2 parents 04ba1f6 + 86b0b35 commit 9711a55
Show file tree
Hide file tree
Showing 80 changed files with 4,401 additions and 683 deletions.
6 changes: 6 additions & 0 deletions src/common/mnemonic-encoding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3379,6 +3379,12 @@ namespace tools
return wordsArray[n];
}

bool valid_word(const std::string& w)
{
auto it = wordsMap.find(w);
return it != wordsMap.end();
}

uint64_t num_by_word(const std::string& w)
{
auto it = wordsMap.find(w);
Expand Down
1 change: 1 addition & 0 deletions src/common/mnemonic-encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ namespace tools
std::string binary2text(const std::vector<unsigned char>& binary);
std::string word_by_num(uint32_t n);
uint64_t num_by_word(const std::string& w);
bool valid_word(const std::string& w);
}
}
72 changes: 61 additions & 11 deletions src/crypto/crypto-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ DISABLE_VS_WARNINGS(4146 4244)

/* Predeclarations */

static void fe_mul(fe, const fe, const fe);
static void fe_sq(fe, const fe);
static void fe_tobytes(unsigned char *, const fe);
void fe_mul(fe, const fe, const fe);
void fe_sq(fe, const fe);
void fe_tobytes(unsigned char *, const fe);
static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
static void ge_p2_0(ge_p2 *);
static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
static void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
static void fe_divpowm1(fe, const fe, const fe);

/* Common functions */
Expand Down Expand Up @@ -48,7 +48,7 @@ static uint64_t load_4(const unsigned char *in)
h = 0
*/

static void fe_0(fe h) {
void fe_0(fe h) {
h[0] = 0;
h[1] = 0;
h[2] = 0;
Expand Down Expand Up @@ -232,7 +232,7 @@ static void fe_copy(fe h, const fe f) {

/* From fe_invert.c */

static void fe_invert(fe out, const fe z) {
void fe_invert(fe out, const fe z) {
fe t0;
fe t1;
fe t2;
Expand Down Expand Up @@ -351,7 +351,7 @@ Can get away with 11 carries, but then data flow is much deeper.
With tighter constraints on inputs can squeeze carries into int32.
*/

static void fe_mul(fe h, const fe f, const fe g) {
void fe_mul(fe h, const fe f, const fe g) {
int32_t f0 = f[0];
int32_t f1 = f[1];
int32_t f2 = f[2];
Expand Down Expand Up @@ -631,7 +631,7 @@ Can overlap h with f.
See fe_mul.c for discussion of implementation strategy.
*/

static void fe_sq(fe h, const fe f) {
void fe_sq(fe h, const fe f) {
int32_t f0 = f[0];
int32_t f1 = f[1];
int32_t f2 = f[2];
Expand Down Expand Up @@ -1005,7 +1005,7 @@ Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
*/

static void fe_tobytes(unsigned char *s, const fe h) {
void fe_tobytes(unsigned char *s, const fe h) {
int32_t h0 = h[0];
int32_t h1 = h[1];
int32_t h2 = h[2];
Expand Down Expand Up @@ -1398,7 +1398,7 @@ void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {

/* From ge_p3_0.c */

static void ge_p3_0(ge_p3 *h) {
void ge_p3_0(ge_p3 *h) {
fe_0(h->X);
fe_1(h->Y);
fe_1(h->Z);
Expand Down Expand Up @@ -1565,7 +1565,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
r = p - q
*/

static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
Expand Down Expand Up @@ -2963,3 +2963,53 @@ int sc_isnonzero(const unsigned char *s) {
s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] |
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
}

// see implmentation of ge_frombytes_vartime above
void fe_frombytes(fe h, const unsigned char *s)
{
/* From fe_frombytes.c */

int64_t h0 = load_4(s);
int64_t h1 = load_3(s + 4) << 6;
int64_t h2 = load_3(s + 7) << 5;
int64_t h3 = load_3(s + 10) << 3;
int64_t h4 = load_3(s + 13) << 2;
int64_t h5 = load_4(s + 16);
int64_t h6 = load_3(s + 20) << 7;
int64_t h7 = load_3(s + 23) << 5;
int64_t h8 = load_3(s + 26) << 4;
int64_t h9 = (load_3(s + 29) & 8388607) << 2;
int64_t carry0;
int64_t carry1;
int64_t carry2;
int64_t carry3;
int64_t carry4;
int64_t carry5;
int64_t carry6;
int64_t carry7;
int64_t carry8;
int64_t carry9;

carry9 = (h9 + (int64_t)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
carry1 = (h1 + (int64_t)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
carry3 = (h3 + (int64_t)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
carry5 = (h5 + (int64_t)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
carry7 = (h7 + (int64_t)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25;

carry0 = (h0 + (int64_t)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
carry2 = (h2 + (int64_t)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
carry4 = (h4 + (int64_t)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
carry6 = (h6 + (int64_t)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
carry8 = (h8 + (int64_t)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26;

h[0] = h0;
h[1] = h1;
h[2] = h2;
h[3] = h3;
h[4] = h4;
h[5] = h5;
h[6] = h6;
h[7] = h7;
h[8] = h8;
h[9] = h9;
}
12 changes: 11 additions & 1 deletion src/crypto/crypto-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,27 @@ void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
void ge_scalarmult_p3(ge_p3 *, const unsigned char *, const ge_p3 *);
void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
void ge_mul8(ge_p1p1 *, const ge_p2 *);
void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
void ge_p3_0(ge_p3 *h);
void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);

extern const fe fe_ma2;
extern const fe fe_ma;
extern const fe fe_fffb1;
extern const fe fe_fffb2;
extern const fe fe_fffb3;
extern const fe fe_fffb4;
void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);

void sc_0(unsigned char *);
void sc_reduce32(unsigned char *);
void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
int sc_check(const unsigned char *);
int sc_isnonzero(const unsigned char *); /* Doesn't normalize */

void fe_sq(fe h, const fe f);
void fe_mul(fe, const fe, const fe);
void fe_frombytes(fe h, const unsigned char *s);
void fe_invert(fe out, const fe z);
void fe_tobytes(unsigned char *s, const fe h);
2 changes: 1 addition & 1 deletion src/crypto/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ namespace crypto {
uint8_t* const m_p_data;
size_t m_data_used;
bool m_ready;
};
}; // class stream_cn_hash

} // namespace crypto

Expand Down
123 changes: 110 additions & 13 deletions src/currency_core/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,42 @@ namespace currency
return m_keys;
}
//-----------------------------------------------------------------
std::string account_base::get_seed_phrase() const
void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password)
{
crypto::chacha8_key key = AUTO_VAL_INIT(key);
crypto::generate_chacha8_key(password, key);
crypto::hash pass_hash = crypto::cn_fast_hash(password.data(), password.size());
crypto::chacha8_iv iv = AUTO_VAL_INIT(iv);
CHECK_AND_ASSERT_THROW_MES(sizeof(pass_hash) >= sizeof(iv), "Invalid configuration: hash size is less than keys_file_data.iv");
iv = *((crypto::chacha8_iv*)&pass_hash);
crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data);
}


std::string account_base::get_seed_phrase(const std::string& password) const
{
if (m_keys_seed_binary.empty())
return "";
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(m_keys_seed_binary);
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp);

std::vector<unsigned char> processed_seed_binary = m_keys_seed_binary;
if (!password.empty())
{
//encrypt seed phrase binary data
crypt_with_pass(&m_keys_seed_binary[0], m_keys_seed_binary.size(), &processed_seed_binary[0], password);
}

std::string keys_seed_text = tools::mnemonic_encoding::binary2text(processed_seed_binary);
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp, !password.empty());

// floor creation time to WALLET_BRAIN_DATE_QUANTUM to make checksum calculation stable
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word);
bool self_check_is_password_used = false;
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word, self_check_is_password_used);
CHECK_AND_ASSERT_THROW_MES(self_check_is_password_used == !password.empty(), "Account seed phrase internal error: password flag encoded wrong");

constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
crypto::hash h = crypto::cn_fast_hash(m_keys_seed_binary.data(), m_keys_seed_binary.size());
std::string binary_for_check_sum((const char*)&m_keys_seed_binary[0], m_keys_seed_binary.size());
binary_for_check_sum.append(password);
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
*reinterpret_cast<uint64_t*>(&h) = creation_timestamp_rounded;
h = crypto::cn_fast_hash(&h, sizeof h);
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
Expand Down Expand Up @@ -104,7 +128,7 @@ namespace currency
return true;
}
//-----------------------------------------------------------------
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase)
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password)
{
//cut the last timestamp word from restore_dats
std::list<std::string> words;
Expand Down Expand Up @@ -135,12 +159,39 @@ namespace currency

uint64_t auditable_flag_and_checksum = UINT64_MAX;
if (!auditable_flag_and_checksum_word.empty())
auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word);
{
try {
auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word);
}
catch (...)
{
return false;
}

}


std::vector<unsigned char> keys_seed_binary = tools::mnemonic_encoding::text2binary(keys_seed_text);
CHECK_AND_ASSERT_MES(keys_seed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security
std::vector<unsigned char> keys_seed_processed_binary = keys_seed_binary;

m_creation_timestamp = get_timstamp_from_word(timestamp_word);

bool has_password = false;
try {
m_creation_timestamp = get_timstamp_from_word(timestamp_word, has_password);
}
catch (...)
{
return false;
}
//double check is password setting from timestamp word match with passed parameters
CHECK_AND_ASSERT_MES(has_password != seed_password.empty(), false, "Seed phrase password wrong interpretation");
if (has_password)
{
CHECK_AND_ASSERT_MES(!seed_password.empty(), false, "Seed phrase password wrong interpretation: internal error");
crypt_with_pass(&keys_seed_binary[0], keys_seed_binary.size(), &keys_seed_processed_binary[0], seed_password);
}

CHECK_AND_ASSERT_MES(keys_seed_processed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security

bool auditable_flag = false;

Expand All @@ -150,25 +201,71 @@ namespace currency
auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit
uint16_t checksum = static_cast<uint16_t>(auditable_flag_and_checksum >> 1); // checksum -- everything else
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size());
std::string binary_for_check_sum((const char*)&keys_seed_processed_binary[0], keys_seed_processed_binary.size());
binary_for_check_sum.append(seed_password);
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
*reinterpret_cast<uint64_t*>(&h) = m_creation_timestamp;
h = crypto::cn_fast_hash(&h, sizeof h);
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
uint16_t checksum_calculated = h_64 % (checksum_max + 1);
CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words");
if (checksum != checksum_calculated)
{
LOG_PRINT_L0("seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words");
return false;
}
}

bool r = restore_keys(keys_seed_binary);
bool r = restore_keys(keys_seed_processed_binary);
CHECK_AND_ASSERT_MES(r, false, "restore_keys failed");

m_keys_seed_binary = keys_seed_binary;
m_keys_seed_binary = keys_seed_processed_binary;

if (auditable_flag)
m_keys.account_address.flags |= ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE;

return true;
}
//-----------------------------------------------------------------
bool account_base::is_seed_tracking(const std::string& seed_phrase)
{
return seed_phrase.find(':') != std::string::npos;
}
//-----------------------------------------------------------------
bool account_base::is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected)
{
//cut the last timestamp word from restore_dats
std::list<std::string> words;
boost::split(words, seed_phrase, boost::is_space());

//let's validate each word
for (const auto& w: words)
{
if (!tools::mnemonic_encoding::valid_word(w))
return false;
}

std::string timestamp_word;
if (words.size() == SEED_PHRASE_V1_WORDS_COUNT)
{
// 24 seed words + one timestamp word = 25 total
timestamp_word = words.back();
}
else if (words.size() == SEED_PHRASE_V2_WORDS_COUNT)
{
// 24 seed words + one timestamp word + one flags & checksum = 26 total
words.erase(--words.end());
timestamp_word = words.back();
}
else
{
return false;
}

get_timstamp_from_word(timestamp_word, is_password_protected);

return true;
}
//-----------------------------------------------------------------
bool account_base::restore_from_tracking_seed(const std::string& tracking_seed)
{
set_null();
Expand Down
6 changes: 4 additions & 2 deletions src/currency_core/account.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ namespace currency
const account_public_address& get_public_address() const { return m_keys.account_address; };
std::string get_public_address_str() const;

std::string get_seed_phrase() const;
std::string get_seed_phrase(const std::string& seed_password) const;
std::string get_tracking_seed() const;
bool restore_from_seed_phrase(const std::string& seed_phrase);
bool restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password);
bool restore_from_tracking_seed(const std::string& tracking_seed);

uint64_t get_createtime() const { return m_creation_timestamp; }
Expand All @@ -78,6 +78,8 @@ namespace currency

static std::string vector_of_chars_to_string(const std::vector<unsigned char>& v) { return std::string(v.begin(), v.end()); }
static std::vector<unsigned char> string_to_vector_of_chars(const std::string& v) { return std::vector<unsigned char>(v.begin(), v.end()); }
static bool is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected);
static bool is_seed_tracking(const std::string& seed_phrase);

BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_keys)
Expand Down
Loading

0 comments on commit 9711a55

Please sign in to comment.