1
// Copyright © 2017-2020 Trust Wallet.
2
//
3
// This file is part of Trust. The full Trust copyright notice, including
4
// terms governing use, modification, and redistribution, is contained in the
5
// file LICENSE at the root of the source code distribution tree.
6

7
#include "Address.h"
8

9
#include "../Base32.h"
10
#include "../Hash.h"
11
#include "../HexCoding.h"
12

13
#include <TrezorCrypto/blake2b.h>
14

15
#include <algorithm>
16
#include <cassert>
17
#include <cmath>
18

19
using namespace TW::Nimiq;
20

21
static const char* BASE32_ALPHABET_NIMIQ = "0123456789ABCDEFGHJKLMNPQRSTUVXY";
22

23
static int check_append(int, uint8_t);
24
static inline int check_add(int, int);
25

26 1
bool Address::isValid(const std::string& stringPadded) {
27
    // Magic check
28 1
    if (stringPadded.substr(0, 2) != "NQ")
29 1
        return false;
30

31 1
    std::string string = stringPadded;
32

33
    // Remove spaces
34 1
    string.erase(std::remove(string.begin(), string.end(), ' '), string.end());
35

36 1
    if (string.length() != 36)
37 1
        return false;
38

39
    // Check if valid Base32
40 1
    Data hash;
41 1
    if (!Base32::decode(string.data() + 4, hash, BASE32_ALPHABET_NIMIQ)) {
42 0
        return false;
43
    }
44

45
    // Calculate checksum
46 1
    int check = 0;
47 1
    for (int i = 4; i < 36; i++)
48 1
        check = check_append(check, string[i]);
49 1
    check = check_add(check, 232600);
50 1
    check = 98 - check;
51

52
    // Get checksum from input
53
    int check_is;
54
    try {
55 1
        check_is = std::stoi(string.substr(2, 2));
56 1
    } catch (const std::invalid_argument& ia) {
57 0
        return false;
58
    }
59

60 1
    if (check_is != check)
61 1
        return false;
62

63 1
    return true;
64
}
65

66 1
Address::Address(const std::string& stringPadded) {
67 1
    if (!isValid(stringPadded)) {
68 0
        throw std::invalid_argument("Invalid address data");
69
    }
70

71 1
    std::string string = stringPadded;
72

73
    // Remove spaces
74 1
    string.erase(std::remove(string.begin(), string.end(), ' '), string.end());
75

76
    // Decode address
77 1
    auto base32 = string.substr(4, 32);
78 1
    Data data;
79 1
    if (!Base32::decode(base32, data, BASE32_ALPHABET_NIMIQ)) {
80 0
        throw std::invalid_argument("Invalid address data");
81
    }
82 1
    if (data.size() != size) {
83 0
        throw std::invalid_argument("Invalid address data");
84
    }
85 1
    std::copy(data.begin(), data.end(), bytes.data());
86
}
87

88 1
Address::Address(const std::vector<uint8_t>& data) {
89 1
    if (!isValid(data)) {
90 0
        throw std::invalid_argument("Invalid address data");
91
    }
92 1
    std::copy(data.begin(), data.end(), bytes.begin());
93
}
94

95 1
Address::Address(const PublicKey& publicKey) {
96 1
    auto hash = std::array<uint8_t, 32>();
97 1
    blake2b(publicKey.bytes.data(), 32, hash.data(), hash.size());
98 1
    std::copy(hash.begin(), hash.begin() + Address::size, bytes.begin());
99
}
100

101 1
std::string Address::string() const {
102
    // Identifier code + blank checksum
103 1
    std::string string = "NQ00";
104
    // Checksum
105 1
    int check = 0;
106

107
    // Calculate Base32 sum
108 1
    Data bytesAsData;
109 1
    bytesAsData.assign(bytes.begin(), bytes.end());
110 1
    auto base32 = Base32::encode(bytesAsData, BASE32_ALPHABET_NIMIQ);
111

112 1
    for (auto i = 0; i < 32; i += 4) {
113
        // Add spaces to output
114 1
        string.append(" ");
115
        // Copy Base32 data
116 1
        string.append(base32.begin() + i, base32.begin() + i + 4);
117
        // Progress checksum state
118 1
        check = check_append(check, base32[i + 0]);
119 1
        check = check_append(check, base32[i + 1]);
120 1
        check = check_append(check, base32[i + 2]);
121 1
        check = check_append(check, base32[i + 3]);
122
    }
123

124
    // Finalize checksum
125 1
    check = check_add(check, 232600); // NQ00
126 1
    check = 98 - check;
127

128
    // Set checksum in address
129 1
    string[2] = '0' + static_cast<uint8_t>((check / 10));
130 1
    string[3] = '0' + (check % 10);
131

132 1
    return string;
133
}
134

135 1
static int check_append(int check, uint8_t c) {
136
    int num;
137 1
    if (c >= '0' && c <= '9')
138 1
        num = c - '0';
139
    else
140 1
        num = c - '7';
141 1
    return check_add(check, num);
142
}
143

144 1
static inline int check_add(int check, int num) {
145 1
    if (num == 0)
146 1
        return (check * 10) % 97;
147

148
    // check = check * 10^(log_10(num))
149 1
    for (int remainder = num; remainder > 0; check *= 10, remainder /= 10)
150
        ;
151 1
    return (check + num) % 97;
152
}

Read our documentation on viewing source code .

Loading