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 "AddressV3.h"
8
#include "AddressV2.h"
9
#include <TrustWalletCore/TWCoinType.h>
10
#include "../Data.h"
11
#include "../Bech32.h"
12
#include "../Base32.h"
13
#include "../Crc.h"
14
#include "../HexCoding.h"
15
#include "../Hash.h"
16

17
#include <array>
18

19
using namespace TW;
20
using namespace TW::Cardano;
21
using namespace std;
22

23 1
bool AddressV3::parseAndCheckV3(const std::string& addr, Discrimination& discrimination, Kind& kind, Data& key1, Data& key2) {
24
    try {
25 1
        auto bech = Bech32::decode(addr);
26 1
        if (bech.second.size() == 0) {
27
            // empty Bech data
28 1
            return false;
29
        }
30
        // Bech bits conversion
31 1
        Data conv;
32 1
        auto success = Bech32::convertBits<5, 8, false>(conv, bech.second);
33 1
        if (!success) {
34 0
            return false;
35
        }
36 1
        if (conv.size() != 33 && conv.size() != 65) {
37 0
            return false;
38
        }
39 1
        discrimination = (Discrimination)((conv[0] & 0b10000000) >> 7);
40 1
        kind = (Kind)(conv[0] & 0b01111111);
41 1
        if (kind <= Kind_Sentinel_Low || kind >= Kind_Sentinel_High) {
42 0
            return false;
43
        }
44 1
        if ((kind == Kind_Group && conv.size() != 65) ||
45 1
            (kind != Kind_Group && conv.size() != 33)) {
46 0
            return false;
47
        }
48

49 1
        switch (kind) {
50
            case Kind_Single:
51
            case Kind_Account:
52
            case Kind_Multisig:
53 1
                assert(conv.size() == 33);
54 1
                key1 = Data(32);
55 1
                std::copy(conv.begin() + 1, conv.begin() + 33, key1.begin());
56 1
                return true;
57

58
            case Kind_Group:
59 1
                assert(conv.size() == 65);
60 1
                key1 = Data(32);
61 1
                key2 = Data(32);
62 1
                std::copy(conv.begin() + 1, conv.begin() + 33, key1.begin());
63 1
                std::copy(conv.begin() + 33, conv.begin() + 65, key2.begin());
64 1
                return true;
65

66
            default:
67 0
                return false;
68
        }
69 1
    } catch (...) {
70 0
        return false;
71
    }
72
}
73

74 1
bool AddressV3::isValid(const std::string& addr) {
75
    Discrimination discrimination;
76
    Kind kind;
77 1
    Data key1;
78 1
    Data key2;
79 1
    if (parseAndCheckV3(addr, discrimination, kind, key1, key2)) {
80 1
        return true;
81
    }
82
    // not V3, try older
83 1
    return AddressV2::isValid(addr);
84
}
85

86 1
AddressV3 AddressV3::createSingle(Discrimination discrimination_in, const Data& spendingKey) {
87 1
    if (spendingKey.size() != 32) {
88 0
        throw std::invalid_argument("Wrong spending key size");
89
    }
90 1
    auto addr = AddressV3();
91 1
    addr.discrimination = discrimination_in;
92 1
    addr.kind = Kind_Single;
93 1
    addr.key1 = spendingKey;
94 1
    return addr;
95
}
96

97 1
AddressV3 AddressV3::createGroup(Discrimination discrimination_in, const Data& spendingKey, const Data& groupKey) {
98 1
    if (spendingKey.size() != 32) {
99 0
        throw std::invalid_argument("Wrong spending key size");
100
    }
101 1
    if (groupKey.size() != 32) {
102 0
        throw std::invalid_argument("Wrong group key size");
103
    }
104 1
    auto addr = AddressV3();
105 1
    addr.discrimination = discrimination_in;
106 1
    addr.kind = Kind_Group;
107 1
    addr.key1 = spendingKey;
108 1
    addr.groupKey = groupKey;
109 1
    return addr;
110
}
111

112 1
AddressV3 AddressV3::createAccount(Discrimination discrimination_in, const Data& accountKey) {
113 1
    if (accountKey.size() != 32) {
114 0
        throw std::invalid_argument("Wrong spending key size");
115
    }
116 1
    auto addr = AddressV3();
117 1
    addr.discrimination = discrimination_in;
118 1
    addr.kind = Kind_Account;
119 1
    addr.key1 = accountKey;
120 1
    return addr;
121
}
122

123 1
AddressV3::AddressV3(const std::string& addr) {
124 1
    if (parseAndCheckV3(addr, discrimination, kind, key1, groupKey)) {
125
        // values stored
126 1
        return;
127
    }
128
    // try legacy
129
    // throw on error
130 1
    legacyAddressV2 = AddressV2(addr);
131
}
132

133 1
AddressV3::AddressV3(const PublicKey& publicKey) {
134
    // input is extended pubkey, 64-byte
135 1
    if (publicKey.type != TWPublicKeyTypeED25519Extended) {
136 0
        throw std::invalid_argument("Invalid public key type");
137
    }
138 1
    discrimination = Discrim_Test;
139 1
    kind = Kind_Group;
140 1
    key1 = Data(32);
141 1
    groupKey = Data(32);
142 1
    std::copy(publicKey.bytes.begin(), publicKey.bytes.begin() + 32, key1.begin());
143 1
    std::copy(publicKey.bytes.begin() + 32, publicKey.bytes.begin() + 64, groupKey.begin());
144
}
145

146 1
AddressV3::AddressV3(const Data& data) {
147
    // min 4 bytes, 2 prefix + 2 len
148 1
    if (data.size() < 4) { throw std::invalid_argument("Address data too short"); }
149 1
    assert(data.size() >= 4);
150 1
    int index = 0;
151 1
    discrimination = (Discrimination)data[index++];
152 1
    kind = (Kind)data[index++];
153
    // key1:
154 1
    byte len1 = data[index++];
155 1
    if (data.size() < 4 + len1) { throw std::invalid_argument("Address data too short"); }
156 1
    assert(data.size() >= 4 + len1);
157 1
    key1 = Data(len1);
158 1
    std::copy(data.begin() + index, data.begin() + index + len1, key1.begin());
159 1
    index += len1;
160
    // groupKey:
161 1
    byte len2 = data[index++];
162 1
    if (data.size() < 4 + len1 + len2) { throw std::invalid_argument("Address data too short"); }
163 1
    assert(data.size() >= 4 + len1 + len2);
164 1
    groupKey = Data(len2);
165 1
    std::copy(data.begin() + index, data.begin() + index + len2, groupKey.begin());
166
}
167

168 1
AddressV3::AddressV3(const AddressV3& other) :
169 1
    discrimination(other.discrimination),
170 1
    kind(other.kind),
171 1
    key1(other.key1),
172 1
    groupKey(other.groupKey),
173 1
    legacyAddressV2(other.legacyAddressV2)
174 1
{}
175

176 1
void AddressV3::operator=(const AddressV3& other)
177
{
178 1
    discrimination = other.discrimination;
179 1
    kind = other.kind;
180 1
    key1 = other.key1;
181 1
    groupKey = other.groupKey;
182 1
    legacyAddressV2 = other.legacyAddressV2;
183
}
184

185 1
string AddressV3::string() const {
186 1
    std::string hrp;
187 1
    switch (kind) {
188
        case Kind_Single:
189
        case Kind_Group:
190
        case Kind_Account:
191 1
            hrp = stringForHRP(TWHRPCardano); break;
192
        default:
193 1
            hrp = ""; break;
194
    }
195 1
    return string(hrp);
196
}
197

198 1
string AddressV3::string(const std::string& hrp) const {
199 1
    if (legacyAddressV2.has_value()) {
200 1
        return legacyAddressV2->string();
201
    }
202

203 1
    byte first = (byte)kind;
204 1
    if (discrimination == Discrim_Test) first = first | 0b10000000;
205 1
    Data keys;
206 1
    TW::append(keys, first);
207 1
    TW::append(keys, key1);
208 1
    if (groupKey.size() > 0) {
209 1
        TW::append(keys, groupKey);
210
    }
211
    // bech
212 1
    Data bech;
213 1
    if (!Bech32::convertBits<8, 5, true>(bech, keys)) {
214 0
        return "";
215
    }
216 1
    return Bech32::encode(hrp, bech);
217
}
218

219 1
string AddressV3::stringBase32() const {
220 1
    if (legacyAddressV2.has_value()) {
221 0
        return legacyAddressV2->string();
222
    }
223

224 1
    byte first = (byte)kind;
225 1
    if (discrimination == Discrim_Test) first = first | 0b10000000;
226 1
    Data keys;
227 1
    TW::append(keys, first);
228 1
    TW::append(keys, key1);
229 1
    if (groupKey.size() > 0) {
230 1
        TW::append(keys, groupKey);
231
    }
232 1
    std::string base32 = Base32::encode(keys, "abcdefghijklmnopqrstuvwxyz23456789");
233 1
    return base32;
234
}
235

236 1
Data AddressV3::data() const {
237 1
    Data data;
238 1
    TW::append(data, (uint8_t)discrimination);
239 1
    TW::append(data, (uint8_t)kind);
240 1
    TW::append(data, (uint8_t)key1.size());
241 1
    TW::append(data, key1);
242 1
    TW::append(data, (uint8_t)groupKey.size());
243 1
    TW::append(data, groupKey);
244 1
    return data;
245
}

Read our documentation on viewing source code .

Loading