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 "AddressV2.h"
8
#include "../Cbor.h"
9
#include "../Data.h"
10
#include "../Base58.h"
11
#include "../Crc.h"
12
#include "../HexCoding.h"
13
#include "../Hash.h"
14

15
#include <array>
16

17
using namespace TW;
18
using namespace TW::Cardano;
19
using namespace std;
20

21 1
bool AddressV2::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs_out, byte& type_out) {
22
    // Decode Bas58, decode payload + crc, decode root, attr
23 1
    Data base58decoded = Base58::bitcoin.decode(addr);
24 1
    if (base58decoded.size() == 0) {
25 1
        throw invalid_argument("Invalid address: could not Base58 decode");
26
    }
27 1
    auto elems = Cbor::Decode(base58decoded).getArrayElements();
28 1
    if (elems.size() < 2) {
29 0
        throw invalid_argument("Could not parse address payload from CBOR data");
30
    }
31 1
    auto tag = elems[0].getTagValue();
32 1
    if (tag != PayloadTag) {
33 0
        throw invalid_argument("wrong tag value");
34
    }
35 1
    Data payload = elems[0].getTagElement().getBytes();
36 1
    uint64_t crcPresent = (uint32_t)elems[1].getValue();
37 1
    uint32_t crcComputed = TW::Crc::crc32(payload);
38 1
    if (crcPresent != crcComputed) {
39 1
        throw invalid_argument("CRC mismatch");
40
    }
41
    // parse payload, 3 elements
42 1
    auto payloadElems = Cbor::Decode(payload).getArrayElements();
43 1
    if (payloadElems.size() < 3) {
44 0
        throw invalid_argument("Could not parse address root and attrs from CBOR data");
45
    }
46 1
    root_out = payloadElems[0].getBytes();
47 1
    attrs_out = payloadElems[1].encoded(); // map, but encoded as bytes
48 1
    type_out = (TW::byte)payloadElems[2].getValue();
49
    return true;
50
}
51

52 1
bool AddressV2::isValid(const std::string& string) {
53
    try {
54 1
        Data root;
55 1
        Data attrs;
56 1
        byte type = 0;
57 1
        if (!parseAndCheck(string, root, attrs, type)) { return false; }
58
        // valid
59 1
        return true;
60 1
    } catch (exception& ex) {
61 1
        return false;
62
    }
63
}
64

65 1
AddressV2::AddressV2(const std::string& string) {
66 1
    if (!parseAndCheck(string, root, attrs, type)) {
67 0
        throw std::invalid_argument("Invalid address string");
68
    }
69
    // values stored
70
}
71

72 1
AddressV2::AddressV2(const PublicKey& publicKey) {
73
    // input is extended pubkey, 64-byte
74 1
    if (publicKey.type != TWPublicKeyTypeED25519Extended) {
75 0
        throw std::invalid_argument("Invalid public key type");
76
    }
77 1
    type = 0; // public key
78 1
    root = keyHash(publicKey.bytes);
79
    // address attributes: empty map for V2, for V1 encrypted derivation path
80 1
    Cbor::Encode emptyMap = Cbor::Encode::map({});
81 1
    attrs = emptyMap.encoded();
82
}
83

84 1
Data AddressV2::getCborData() const {
85
    // put together string represenatation, CBOR representation
86
    // inner data: pubkey, attrs, type
87 1
    auto cbor1 = Cbor::Encode::array({
88 1
        Cbor::Encode::bytes(root),
89 1
        Cbor::Encode::fromRaw(attrs),
90 1
        Cbor::Encode::uint(type),
91
    });
92 1
    auto payloadData = cbor1.encoded();
93
    
94
    // crc checksum 
95 1
    auto crc = TW::Crc::crc32(payloadData);
96
    // second pack: tag, base, crc
97 1
    auto cbor2 = Cbor::Encode::array({
98 1
        Cbor::Encode::tag(PayloadTag, Cbor::Encode::bytes(payloadData)),
99 1
        Cbor::Encode::uint(crc),
100
    });
101 1
    return cbor2.encoded();
102
}
103

104 1
string AddressV2::string() const {
105
    // Base58 encode the CBOR data
106 1
    return Base58::bitcoin.encode(getCborData());
107
}
108

109 1
Data AddressV2::keyHash(const TW::Data& xpub) {
110 1
    if (xpub.size() != 64) { throw invalid_argument("invalid xbub length"); }
111
    // hash of follwoing Cbor-array: [0, [0, xbub], {} ]
112
    // 3rd entry map is empty map for V2, contains derivation path for V1
113 1
    Data cborData = Cbor::Encode::array({
114 1
        Cbor::Encode::uint(0),
115 1
        Cbor::Encode::array({
116 1
            Cbor::Encode::uint(0),
117 1
            Cbor::Encode::bytes(xpub)
118
        }),
119 1
        Cbor::Encode::map({}),
120 1
    }).encoded();
121
    // SHA3 hash, then blake
122 1
    Data firstHash = Hash::sha3_256(cborData);
123 1
    Data blake = Hash::blake2b(firstHash, 28);
124 1
    return blake;
125
}

Read our documentation on viewing source code .

Loading