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 "CashAddress.h"
8
#include "../Coin.h"
9

10
#include <TrezorCrypto/cash_addr.h>
11
#include <TrezorCrypto/ecdsa.h>
12

13
#include <array>
14
#include <cassert>
15
#include <cstring>
16

17
using namespace TW::Bitcoin;
18

19
/// Cash address human-readable part
20 1
static const std::string cashHRP = "bitcoincash";
21

22
/// From https://github.com/bitcoincashorg/bitcoincash.org/blob/master/spec/cashaddr.md
23

24
static const uint8_t p2khVersion = 0x00;
25
static const uint8_t p2shVersion = 0x08;
26

27
static constexpr size_t maxHRPSize = 20;
28
static constexpr size_t maxDataSize = 104;
29

30 1
bool CashAddress::isValid(const std::string& string) {
31 1
    auto withPrefix = string;
32 1
    if (!std::equal(cashHRP.begin(), cashHRP.end(), string.begin())) {
33 1
        withPrefix = cashHRP + ":" + string;
34
    }
35

36 1
    std::array<char, maxHRPSize + 1> hrp = {0};
37
    std::array<uint8_t, maxDataSize> data;
38
    size_t dataLen;
39 1
    if (cash_decode(hrp.data(), data.data(), &dataLen, withPrefix.c_str()) == 0 || dataLen != CashAddress::size) {
40 1
        return false;
41
    }
42 1
    if (std::strncmp(hrp.data(), cashHRP.c_str(), std::min(cashHRP.size(), maxHRPSize)) != 0) {
43 0
        return false;
44
    }
45 1
    return true;
46
}
47

48 1
CashAddress::CashAddress(const std::string& string) {
49 1
    auto withPrefix = string;
50 1
    if (!std::equal(cashHRP.begin(), cashHRP.end(), string.begin())) {
51 1
        withPrefix = cashHRP + ":" + string;
52
    }
53

54
    std::array<char, maxHRPSize + 1> hrp;
55
    std::array<uint8_t, maxDataSize> data;
56
    size_t dataLen;
57 1
    auto success = cash_decode(hrp.data(), data.data(), &dataLen, withPrefix.c_str()) != 0;
58 1
    if (!success || std::strncmp(hrp.data(), cashHRP.c_str(), std::min(cashHRP.size(), maxHRPSize)) != 0 || dataLen != CashAddress::size) {
59 0
        throw std::invalid_argument("Invalid address string");
60
    }
61 1
    std::copy(data.begin(), data.begin() + dataLen, bytes.begin());
62
}
63

64 0
CashAddress::CashAddress(const std::vector<uint8_t>& data) {
65 0
    if (!isValid(data)) {
66 0
        throw std::invalid_argument("Invalid address key data");
67
    }
68 0
    std::copy(data.begin(), data.end(), bytes.begin());
69
}
70

71 1
CashAddress::CashAddress(const PublicKey& publicKey) {
72 1
    if (publicKey.type != TWPublicKeyTypeSECP256k1) {
73 0
        throw std::invalid_argument("CashAddress needs a compressed SECP256k1 public key.");
74
    }
75
    std::array<uint8_t, 21> payload;
76 1
    payload[0] = 0;
77 1
    ecdsa_get_pubkeyhash(publicKey.bytes.data(), HASHER_SHA2_RIPEMD, payload.data() + 1);
78

79 1
    size_t outlen = 0;
80 1
    auto success = cash_addr_to_data(bytes.data(), &outlen, payload.data(), 21) != 0;
81 1
    if (!success || outlen != CashAddress::size) {
82 0
        throw std::invalid_argument("unable to cash_addr_to_data");
83
    }
84
}
85

86 1
std::string CashAddress::string() const {
87
    std::array<char, 129> result;
88 1
    cash_encode(result.data(), cashHRP.c_str(), bytes.data(), CashAddress::size);
89 1
    return result.data();
90
}
91

92 1
Address CashAddress::legacyAddress() const {
93 1
    std::vector<uint8_t> result(Address::size);
94 1
    size_t outlen = 0;
95 1
    cash_data_to_addr(result.data(), &outlen, bytes.data(), CashAddress::size);
96 1
    assert(outlen == 21 && "Invalid length");
97 1
    if (result[0] == p2khVersion) {
98 1
        result[0] = TW::p2pkhPrefix(TWCoinTypeBitcoinCash);
99 1
    } else if (result[0] == p2shVersion) {
100 1
        result[0] = TW::p2shPrefix(TWCoinTypeBitcoinCash);
101
    }
102 1
    return Address(result);
103
}

Read our documentation on viewing source code .

Loading