trustwallet / wallet-core

@@ -100,23 +100,28 @@
Loading
100 100
    bool ok = true;
101 101
    for (size_t i = 0; ok && i < str.size(); ++i) {
102 102
        unsigned char c = str[i];
103 -
        if (c < 33 || c > 126)
103 +
        if (c < 33 || c > 126) {
104 104
            ok = false;
105 -
        if (c >= 'a' && c <= 'z')
105 +
        }
106 +
        if (c >= 'a' && c <= 'z') {
106 107
            lower = true;
107 -
        if (c >= 'A' && c <= 'Z')
108 +
        }
109 +
        if (c >= 'A' && c <= 'Z') {
108 110
            upper = true;
111 +
        }
109 112
    }
110 -
    if (lower && upper)
113 +
    if (lower && upper) {
111 114
        ok = false;
115 +
    }
112 116
    size_t pos = str.rfind('1');
113 117
    if (ok && str.size() <= 120 && pos != str.npos && pos >= 1 && pos + 7 <= str.size()) {
114 118
        Data values;
115 119
        values.resize(str.size() - 1 - pos);
116 120
        for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
117 121
            unsigned char c = str[i + pos + 1];
118 -
            if (charset_rev[c] == -1)
122 +
            if (charset_rev[c] == -1) {
119 123
                ok = false;
124 +
            }
120 125
            values[i] = charset_rev[c];
121 126
        }
122 127
        if (ok) {

@@ -93,10 +93,10 @@
Loading
93 93
    case TWCoinTypeLitecoin:
94 94
    case TWCoinTypeViacoin: {
95 95
        auto decoded = Bitcoin::SegwitAddress::decode(string);
96 -
        if (!decoded.second) {
96 +
        if (!std::get<2>(decoded)) {
97 97
            break;
98 98
        }
99 -
        data = decoded.first.witnessProgram;
99 +
        data = std::get<0>(decoded).witnessProgram;
100 100
        break;
101 101
    }
102 102

@@ -10,11 +10,13 @@
Loading
10 10
11 11
#include <cstdint>
12 12
#include <string>
13 +
#include <tuple>
13 14
14 15
namespace TW::Bitcoin {
15 16
16 17
/// A Segwit address.
17 18
/// Note: Similar to Bech32Address, but it differs enough so that reuse makes no sense.
19 +
/// See BIP173 https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
18 20
class SegwitAddress {
19 21
  public:
20 22
    /// Human-readable part.
@@ -45,8 +47,8 @@
Loading
45 47
46 48
    /// Decodes a SegWit address.
47 49
    ///
48 -
    /// \returns a pair with the address and a success flag.
49 -
    static std::pair<SegwitAddress, bool> decode(const std::string& addr);
50 +
    /// \returns a tuple with the address, hrp, and a success flag.
51 +
    static std::tuple<SegwitAddress, std::string, bool> decode(const std::string& addr);
50 52
51 53
    /// Encodes the SegWit address.
52 54
    ///

@@ -14,37 +14,20 @@
Loading
14 14
using namespace TW::Bitcoin;
15 15
16 16
bool SegwitAddress::isValid(const std::string& string) {
17 -
    auto dec = Bech32::decode(string);
18 -
    if (dec.second.empty()) {
19 -
        return false;
20 -
    }
21 -
22 -
    Data conv;
23 -
    if (!Bech32::convertBits<5, 8, false>(conv, Data(dec.second.begin() + 1, dec.second.end())) ||
24 -
        conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 ||
25 -
        (dec.second[0] == 0 && conv.size() != 20 && conv.size() != 32)) {
26 -
        return false;
27 -
    }
28 -
29 -
    return true;
17 +
    return std::get<2>(decode(string));
30 18
}
31 19
32 20
bool SegwitAddress::isValid(const std::string& string, const std::string& hrp) {
33 -
    auto dec = Bech32::decode(string);
34 -
    if (dec.second.empty()) {
21 +
    auto decoded = decode(string);
22 +
    if (!std::get<2>(decoded)) {
35 23
        return false;
36 24
    }
25 +
    // extra step to check hrp
26 +
    auto dec = Bech32::decode(string);
37 27
    if (dec.first != hrp) {
38 28
        return false;
39 29
    }
40 30
41 -
    Data conv;
42 -
    if (!Bech32::convertBits<5, 8, false>(conv, Data(dec.second.begin() + 1, dec.second.end())) ||
43 -
        conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 ||
44 -
        (dec.second[0] == 0 && conv.size() != 20 && conv.size() != 32)) {
45 -
        return false;
46 -
    }
47 -
48 31
    return true;
49 32
}
50 33
@@ -58,20 +41,23 @@
Loading
58 41
                         witnessProgram.data());
59 42
}
60 43
61 -
std::pair<SegwitAddress, bool> SegwitAddress::decode(const std::string& addr) {
44 +
std::tuple<SegwitAddress, std::string, bool> SegwitAddress::decode(const std::string& addr) {
45 +
    auto resp = std::make_tuple(SegwitAddress(), "", false);
62 46
    auto dec = Bech32::decode(addr);
63 47
    if (dec.second.empty()) {
64 -
        return std::make_pair(SegwitAddress(), false);
48 +
        // bech32 decode fails, or decoded data is empty
49 +
        return resp;
65 50
    }
51 +
    assert(dec.second.size() >= 1);
66 52
67 -
    Data conv;
68 -
    if (!Bech32::convertBits<5, 8, false>(conv, Data(dec.second.begin() + 1, dec.second.end())) ||
69 -
        conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 ||
70 -
        (dec.second[0] == 0 && conv.size() != 20 && conv.size() != 32)) {
71 -
        return std::make_pair(SegwitAddress(), false);
53 +
    // First byte is Segwit version
54 +
    // Only version 0 is currently supported; BIP173 BIP350
55 +
    if (dec.second[0] != 0) {
56 +
        return resp;
72 57
    }
73 58
74 -
    return std::make_pair(SegwitAddress(dec.first, dec.second[0], conv), true);
59 +
    auto raw = fromRaw(dec.first, dec.second);
60 +
    return std::make_tuple(raw.first, dec.first, raw.second);
75 61
}
76 62
77 63
std::string SegwitAddress::string() const {
@@ -79,7 +65,7 @@
Loading
79 65
    enc.push_back(static_cast<uint8_t>(witnessVersion));
80 66
    Bech32::convertBits<8, 5, true>(enc, witnessProgram);
81 67
    std::string result = Bech32::encode(hrp, enc);
82 -
    if (!decode(result).second) {
68 +
    if (!std::get<2>(decode(result))) {
83 69
        return {};
84 70
    }
85 71
    return result;
@@ -87,11 +73,16 @@
Loading
87 73
88 74
std::pair<SegwitAddress, bool> SegwitAddress::fromRaw(const std::string& hrp,
89 75
                                                      const std::vector<uint8_t>& data) {
76 +
    auto resp = std::make_pair(SegwitAddress(), false);
77 +
    if (data.size() == 0) {
78 +
        return resp;
79 +
    }
80 +
    byte segwitVersion = data[0];
90 81
    Data conv;
91 82
    if (!Bech32::convertBits<5, 8, false>(conv, Data(data.begin() + 1, data.end())) ||
92 -
        conv.size() < 2 || conv.size() > 40 || data[0] > 16 ||
93 -
        (data[0] == 0 && conv.size() != 20 && conv.size() != 32)) {
94 -
        return std::make_pair(SegwitAddress(), false);
83 +
        conv.size() < 2 || conv.size() > 40 || segwitVersion > 16 ||
84 +
        (segwitVersion == 0 && conv.size() != 20 && conv.size() != 32)) {
85 +
        return resp;
95 86
    }
96 87
97 88
    return std::make_pair(SegwitAddress(hrp, data[0], conv), true);

@@ -273,7 +273,7 @@
Loading
273 273
    } else if (SegwitAddress::isValid(string)) {
274 274
        auto result = SegwitAddress::decode(string);
275 275
        // address starts with bc/ltc
276 -
        auto program = result.first.witnessProgram;
276 +
        auto program = std::get<0>(result).witnessProgram;
277 277
        return buildPayToWitnessProgram(program);
278 278
    } else if (CashAddress::isValid(string)) {
279 279
        auto address = CashAddress(string);

@@ -27,11 +27,11 @@
Loading
27 27
struct TWSegwitAddress *_Nullable TWSegwitAddressCreateWithString(TWString *_Nonnull string) {
28 28
    auto s = reinterpret_cast<const std::string*>(string);
29 29
    auto dec = SegwitAddress::decode(*s);
30 -
    if (!dec.second) {
30 +
    if (!std::get<2>(dec)) {
31 31
        return nullptr;
32 32
    }
33 33
34 -
    return new TWSegwitAddress{ std::move(dec.first) };
34 +
    return new TWSegwitAddress{ std::move(std::get<0>(dec)) };
35 35
}
36 36
37 37
struct TWSegwitAddress *_Nonnull TWSegwitAddressCreateWithPublicKey(enum TWHRP hrp, struct TWPublicKey *_Nonnull publicKey) {
Files Coverage
src 95.42%
walletconsole/lib 94.71%
Project Totals (441 files) 95.39%
1
codecov:
2
  require_ci_to_pass: yes
3

4
coverage:
5
  precision: 2
6
  round: down
7
  range: "70...100"
8
  status:
9
    project:
10
      default:
11
        informational: true
12

13
parsers:
14
  gcov:
15
    branch_detection:
16
      conditional: yes
17
      loop: yes
18
      method: no
19
      macro: no
20

21
comment:
22
  layout: "reach,diff,flags,files,footer"
23
  behavior: default
24
  require_changes: no
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading