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 "PublicKey.h"
8
#include "Data.h"
9

10
#include <TrezorCrypto/ecdsa.h>
11
#include <TrezorCrypto/ed25519-donna/ed25519-blake2b.h>
12
#include <TrezorCrypto/nist256p1.h>
13
#include <TrezorCrypto/secp256k1.h>
14
#include <TrezorCrypto/sodium/keypair.h>
15

16
namespace TW {
17

18
/// Determines if a collection of bytes makes a valid public key of the
19
/// given type.
20 1
bool PublicKey::isValid(const Data& data, enum TWPublicKeyType type) {
21 1
    const auto size = data.size();
22 1
    if (size == 0) {
23 1
        return false;
24
    }
25 1
    switch (type) {
26
    case TWPublicKeyTypeED25519:
27 1
        return size == ed25519Size || (size == ed25519Size + 1 && data[0] == 0x01);
28
    case TWPublicKeyTypeCURVE25519:
29
    case TWPublicKeyTypeED25519Blake2b:
30 1
        return size == ed25519Size;
31
    case TWPublicKeyTypeED25519Extended:
32 1
        return size == ed25519ExtendedSize;
33
    case TWPublicKeyTypeSECP256k1:
34
    case TWPublicKeyTypeNIST256p1:
35 1
        return size == secp256k1Size && (data[0] == 0x02 || data[0] == 0x03);
36
    case TWPublicKeyTypeSECP256k1Extended:
37
    case TWPublicKeyTypeNIST256p1Extended:
38 1
        return size == secp256k1ExtendedSize && data[0] == 0x04;
39
    default:
40 1
        return false;
41
    }
42
}
43

44
/// Initializes a public key with a collection of bytes.
45
///
46
/// @throws std::invalid_argument if the data is not a valid public key.
47 1
PublicKey::PublicKey(const Data& data, enum TWPublicKeyType type) : type(type) {
48 1
    if (!isValid(data, type)) {
49 1
        throw std::invalid_argument("Invalid public key data");
50
    }
51 1
    switch (type) {
52
    case TWPublicKeyTypeSECP256k1:
53
    case TWPublicKeyTypeNIST256p1:
54
    case TWPublicKeyTypeSECP256k1Extended:
55
    case TWPublicKeyTypeNIST256p1Extended:
56 1
        bytes.reserve(data.size());
57 1
        std::copy(std::begin(data), std::end(data), std::back_inserter(bytes));
58 1
        break;
59

60
    case TWPublicKeyTypeED25519:
61
    case TWPublicKeyTypeCURVE25519:
62 1
        bytes.reserve(ed25519Size);
63 1
        if (data.size() == ed25519Size + 1) {
64 1
            std::copy(std::begin(data) + 1, std::end(data), std::back_inserter(bytes));
65 1
        } else {
66 1
            std::copy(std::begin(data), std::end(data), std::back_inserter(bytes));
67
        }
68 1
        break;
69
    case TWPublicKeyTypeED25519Blake2b:
70 1
        bytes.reserve(ed25519Size);
71 1
        assert(data.size() == ed25519Size); // ensured by isValid() above
72 1
        std::copy(std::begin(data), std::end(data), std::back_inserter(bytes));
73 1
        break;
74
    case TWPublicKeyTypeED25519Extended:
75 1
        bytes.reserve(ed25519ExtendedSize);
76 1
        std::copy(std::begin(data), std::end(data), std::back_inserter(bytes));
77
    }
78
}
79

80 1
PublicKey PublicKey::compressed() const {
81 1
    if (type != TWPublicKeyTypeSECP256k1Extended && type != TWPublicKeyTypeNIST256p1Extended) {
82 1
        return *this;
83
    }
84

85 1
    Data newBytes(secp256k1Size);
86 1
    assert(bytes.size() >= 65);
87 1
    newBytes[0] = 0x02 | (bytes[64] & 0x01);
88

89 1
    assert(type == TWPublicKeyTypeSECP256k1Extended || type == TWPublicKeyTypeNIST256p1Extended);
90 1
    switch (type) {
91
    case TWPublicKeyTypeSECP256k1Extended:
92 1
        std::copy(bytes.begin() + 1, bytes.begin() + secp256k1Size, newBytes.begin() + 1);
93 1
        return PublicKey(newBytes, TWPublicKeyTypeSECP256k1);
94

95
    case TWPublicKeyTypeNIST256p1Extended:
96
    default:
97 1
        std::copy(bytes.begin() + 1, bytes.begin() + secp256k1Size, newBytes.begin() + 1);
98 1
        return PublicKey(newBytes, TWPublicKeyTypeNIST256p1);
99
    }
100
}
101

102 1
PublicKey PublicKey::extended() const {
103 1
    Data newBytes(secp256k1ExtendedSize);
104 1
    switch (type) {
105
    case TWPublicKeyTypeSECP256k1:
106 1
        ecdsa_uncompress_pubkey(&secp256k1, bytes.data(), newBytes.data());
107 1
        return PublicKey(newBytes, TWPublicKeyTypeSECP256k1Extended);
108
    case TWPublicKeyTypeSECP256k1Extended:
109 1
        return *this;
110
    case TWPublicKeyTypeNIST256p1:
111 1
        ecdsa_uncompress_pubkey(&nist256p1, bytes.data(), newBytes.data());
112 1
        return PublicKey(newBytes, TWPublicKeyTypeNIST256p1Extended);
113
    case TWPublicKeyTypeNIST256p1Extended:
114 1
        return *this;
115
    case TWPublicKeyTypeED25519:
116
    case TWPublicKeyTypeCURVE25519:
117
    case TWPublicKeyTypeED25519Blake2b:
118
    case TWPublicKeyTypeED25519Extended:
119 1
       return *this;
120
    }
121
}
122

123 1
bool PublicKey::verify(const Data& signature, const Data& message) const {
124 1
    switch (type) {
125
    case TWPublicKeyTypeSECP256k1:
126
    case TWPublicKeyTypeSECP256k1Extended:
127 1
        return ecdsa_verify_digest(&secp256k1, bytes.data(), signature.data(), message.data()) == 0;
128
    case TWPublicKeyTypeNIST256p1:
129
    case TWPublicKeyTypeNIST256p1Extended:
130 1
        return ecdsa_verify_digest(&nist256p1, bytes.data(), signature.data(), message.data()) == 0;
131
    case TWPublicKeyTypeED25519:
132 1
        return ed25519_sign_open(message.data(), message.size(), bytes.data(), signature.data()) == 0;
133
    case TWPublicKeyTypeED25519Blake2b:
134 1
        return ed25519_sign_open_blake2b(message.data(), message.size(), bytes.data(), signature.data()) == 0;
135
    case TWPublicKeyTypeED25519Extended:
136 0
        throw std::logic_error("Not yet implemented");
137
        //ed25519_sign_open(message.data(), message.size(), bytes.data(), signature.data()) == 0;
138
    case TWPublicKeyTypeCURVE25519:
139 1
        auto ed25519PublicKey = Data();
140 1
        ed25519PublicKey.resize(PublicKey::ed25519Size);
141 1
        curve25519_pk_to_ed25519(ed25519PublicKey.data(), bytes.data());
142

143 1
        ed25519PublicKey[31] &= 0x7F;
144 1
        ed25519PublicKey[31] |= signature[63] & 0x80;
145

146
        // remove sign bit
147 1
        auto verifyBuffer = Data();
148 1
        append(verifyBuffer, signature);
149 1
        verifyBuffer[63] &= 127;
150 1
        return ed25519_sign_open(message.data(), message.size(), ed25519PublicKey.data(),
151 1
                                 verifyBuffer.data()) == 0;
152
    }
153
}
154

155 1
bool PublicKey::verifySchnorr(const Data& signature, const Data& message) const {
156 1
    switch (type) {
157
    case TWPublicKeyTypeSECP256k1:
158
    case TWPublicKeyTypeSECP256k1Extended:
159 1
        return zil_schnorr_verify(&secp256k1, bytes.data(), signature.data(), message.data(), static_cast<uint32_t>(message.size())) == 0;
160
    case TWPublicKeyTypeNIST256p1:
161
    case TWPublicKeyTypeNIST256p1Extended:
162
    case TWPublicKeyTypeED25519:
163
    case TWPublicKeyTypeED25519Blake2b:
164
    case TWPublicKeyTypeED25519Extended:
165
    case TWPublicKeyTypeCURVE25519:
166
    default:
167 1
        return false;
168
    }
169
}
170

171 1
Data PublicKey::hash(const Data& prefix, Hash::Hasher hasher, bool skipTypeByte) const {
172 1
    const auto offset = std::size_t(skipTypeByte ? 1 : 0);
173 1
    const auto hash = hasher(bytes.data() + offset, bytes.size() - offset);
174

175 1
    auto result = Data();
176 1
    result.reserve(prefix.size() + hash.size());
177 1
    append(result, prefix);
178 1
    append(result, hash);
179 1
    return result;
180
}
181

182 1
PublicKey PublicKey::recover(const Data& signature, const Data& message) {
183 1
    if (signature.size() < 65) {
184 1
        throw std::invalid_argument("signature too short");
185
    }
186 1
    auto v = signature[64];
187 1
    if (v >= 27) {
188 1
        v -= 27;
189
    }
190 1
    TW::Data result(65);
191 1
    if (ecdsa_recover_pub_from_sig(&secp256k1, result.data(), signature.data(), message.data(), v) != 0) {
192 0
        throw std::invalid_argument("recover failed");
193
    }
194 1
    return PublicKey(result, TWPublicKeyTypeSECP256k1Extended);
195
}
196

197
} // namespace TW

Read our documentation on viewing source code .

Loading