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
#pragma once
8

9
#include "Base58.h"
10
#include "Data.h"
11
#include "PublicKey.h"
12

13
#include <array>
14
#include <string>
15
#include <iostream>
16

17 1
const std::string SS58Prefix = "SS58PRE";
18

19
namespace TW {
20

21
class SS58Address {
22
  public:
23
    /// Number of bytes in an address.
24
    static const size_t size = 33;
25

26
    static const size_t checksumSize = 2;
27

28
    /// Address data consisting of a network byte followed by the public key.
29
    std::array<byte, size> bytes;
30

31
    /// Determines whether a string makes a valid address
32 1
    static bool isValid(const std::string& string, byte network) {
33 1
        const auto decoded = Base58::bitcoin.decode(string);
34 1
        if (decoded.size() != SS58Address::size + checksumSize) {
35 1
            return false;
36
        }
37
        // check network
38 1
        if (decoded[0] != network) {
39 1
            return false;
40
        }
41 1
        auto checksum = computeChecksum(Data(decoded.begin(), decoded.end() - checksumSize));
42
        // compare checksum
43 1
        if (!std::equal(decoded.end() - checksumSize, decoded.end(), checksum.begin())) {
44 0
            return false;
45
        }
46 1
        return true;
47
    }
48

49
    template <typename T>
50 1
    static Data computeChecksum(const T& data) {
51 1
        auto prefix = Data(SS58Prefix.begin(), SS58Prefix.end());
52 1
        append(prefix, Data(data.begin(), data.end()));
53 1
        auto hash = Hash::blake2b(prefix, 64);
54 1
        auto checksum = Data(checksumSize);
55 1
        std::copy(hash.begin(), hash.begin() + checksumSize, checksum.data());
56 1
        return checksum;
57
    }
58

59
    SS58Address() = default;
60

61
    /// Initializes an address with a string representation.
62 1
    SS58Address(const std::string& string, byte network) {
63 1
        if (!isValid(string, network)) {
64 0
            throw std::invalid_argument("Invalid address string");
65
        }
66 1
        const auto decoded = Base58::bitcoin.decode(string);
67 1
        std::copy(decoded.begin(), decoded.end() - checksumSize, bytes.begin());
68
    }
69

70
    /// Initializes an address with a public key and network.
71 1
    SS58Address(const PublicKey& publicKey, byte network) {
72 1
        if (publicKey.type != TWPublicKeyTypeED25519) {
73 0
            throw std::invalid_argument("SS58Address expects an ed25519 public key.");
74
        }
75 1
        bytes[0] = network;
76 1
        std::copy(publicKey.bytes.begin(), publicKey.bytes.end(), bytes.begin() + 1);
77
    }
78

79
    /// Returns a string representation of the address.
80 1
    std::string string() const {
81 1
        auto result = Data(bytes.begin(), bytes.end());
82 1
        auto checksum = computeChecksum(bytes);
83 1
        append(result, checksum);
84 1
        return Base58::bitcoin.encode(result);
85
    }
86
};
87

88
inline bool operator==(const SS58Address& lhs, const SS58Address& rhs) {
89
    return lhs.bytes == rhs.bytes;
90
}
91

92
} // namespace TW

Read our documentation on viewing source code .

Loading