forked from trustwallet/wallet-core
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAddress.cpp
More file actions
152 lines (121 loc) · 4.02 KB
/
Copy pathAddress.cpp
File metadata and controls
152 lines (121 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright © 2017-2020 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
#include "Address.h"
#include "../Base32.h"
#include "../Hash.h"
#include "../HexCoding.h"
#include <TrezorCrypto/blake2b.h>
#include <algorithm>
#include <cassert>
#include <cmath>
using namespace TW::Nimiq;
static const char* BASE32_ALPHABET_NIMIQ = "0123456789ABCDEFGHJKLMNPQRSTUVXY";
static int check_append(int, uint8_t);
static inline int check_add(int, int);
bool Address::isValid(const std::string& stringPadded) {
// Magic check
if (stringPadded.substr(0, 2) != "NQ")
return false;
std::string string = stringPadded;
// Remove spaces
string.erase(std::remove(string.begin(), string.end(), ' '), string.end());
if (string.length() != 36)
return false;
// Check if valid Base32
Data hash;
if (!Base32::decode(string.data() + 4, hash, BASE32_ALPHABET_NIMIQ)) {
return false;
}
// Calculate checksum
int check = 0;
for (int i = 4; i < 36; i++)
check = check_append(check, string[i]);
check = check_add(check, 232600);
check = 98 - check;
// Get checksum from input
int check_is;
try {
check_is = std::stoi(string.substr(2, 2));
} catch (const std::invalid_argument& ia) {
return false;
}
if (check_is != check)
return false;
return true;
}
Address::Address(const std::string& stringPadded) {
if (!isValid(stringPadded)) {
throw std::invalid_argument("Invalid address data");
}
std::string string = stringPadded;
// Remove spaces
string.erase(std::remove(string.begin(), string.end(), ' '), string.end());
// Decode address
auto base32 = string.substr(4, 32);
Data data;
if (!Base32::decode(base32, data, BASE32_ALPHABET_NIMIQ)) {
throw std::invalid_argument("Invalid address data");
}
if (data.size() != size) {
throw std::invalid_argument("Invalid address data");
}
std::copy(data.begin(), data.end(), bytes.data());
}
Address::Address(const std::vector<uint8_t>& data) {
if (!isValid(data)) {
throw std::invalid_argument("Invalid address data");
}
std::copy(data.begin(), data.end(), bytes.begin());
}
Address::Address(const PublicKey& publicKey) {
auto hash = std::array<uint8_t, 32>();
blake2b(publicKey.bytes.data(), 32, hash.data(), hash.size());
std::copy(hash.begin(), hash.begin() + Address::size, bytes.begin());
}
std::string Address::string() const {
// Identifier code + blank checksum
std::string string = "NQ00";
// Checksum
int check = 0;
// Calculate Base32 sum
Data bytesAsData;
bytesAsData.assign(bytes.begin(), bytes.end());
auto base32 = Base32::encode(bytesAsData, BASE32_ALPHABET_NIMIQ);
for (auto i = 0; i < 32; i += 4) {
// Add spaces to output
string.append(" ");
// Copy Base32 data
string.append(base32.begin() + i, base32.begin() + i + 4);
// Progress checksum state
check = check_append(check, base32[i + 0]);
check = check_append(check, base32[i + 1]);
check = check_append(check, base32[i + 2]);
check = check_append(check, base32[i + 3]);
}
// Finalize checksum
check = check_add(check, 232600); // NQ00
check = 98 - check;
// Set checksum in address
string[2] = '0' + static_cast<uint8_t>((check / 10));
string[3] = '0' + (check % 10);
return string;
}
static int check_append(int check, uint8_t c) {
int num;
if (c >= '0' && c <= '9')
num = c - '0';
else
num = c - '7';
return check_add(check, num);
}
static inline int check_add(int check, int num) {
if (num == 0)
return (check * 10) % 97;
// check = check * 10^(log_10(num))
for (int remainder = num; remainder > 0; check *= 10, remainder /= 10)
;
return (check + num) % 97;
}