Line data Source code
1 : // Copyright (c) 2016-2018 The Zcash developers
2 : // Copyright (c) 2020 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "sapling/key_io_sapling.h"
7 :
8 : #include "utilstrencodings.h"
9 : #include "bech32.h"
10 : #include "script/script.h"
11 : #include "streams.h"
12 :
13 : #include <boost/variant/apply_visitor.hpp>
14 : #include <boost/variant/static_visitor.hpp>
15 :
16 : #include <assert.h>
17 : #include <string.h>
18 : #include <algorithm>
19 :
20 : class PaymentAddressEncoder : public boost::static_visitor<std::string>
21 : {
22 : private:
23 : const CChainParams& m_params;
24 :
25 : public:
26 10211 : explicit PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
27 :
28 10211 : std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const
29 : {
30 10211 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
31 10211 : ss << zaddr;
32 : // ConvertBits requires unsigned char, but CDataStream uses char
33 20422 : std::vector<unsigned char> seraddr(ss.begin(), ss.end());
34 20422 : std::vector<unsigned char> data;
35 : // See calculation comment below
36 10211 : data.reserve((seraddr.size() * 8 + 4) / 5);
37 714770 : ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
38 20422 : return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data);
39 : }
40 :
41 0 : std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
42 : };
43 :
44 : class ViewingKeyEncoder : public boost::static_visitor<std::string>
45 : {
46 : private:
47 : const CChainParams& m_params;
48 :
49 : public:
50 1003 : explicit ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
51 :
52 1003 : std::string operator()(const libzcash::SaplingExtendedFullViewingKey& extfvk) const
53 : {
54 1003 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
55 1003 : ss << extfvk;
56 : // ConvertBits requires unsigned char, but CDataStream uses char
57 2006 : std::vector<unsigned char> serkey(ss.begin(), ss.end());
58 2006 : std::vector<unsigned char> data;
59 : // See calculation comment below
60 1003 : data.reserve((serkey.size() * 8 + 4) / 5);
61 272816 : ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
62 1003 : std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK), data);
63 1003 : memory_cleanse(serkey.data(), serkey.size());
64 1003 : memory_cleanse(data.data(), data.size());
65 2006 : return ret;
66 : }
67 :
68 0 : std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
69 : };
70 :
71 : class SpendingKeyEncoder : public boost::static_visitor<std::string>
72 : {
73 : private:
74 : const CChainParams& m_params;
75 :
76 : public:
77 4005 : explicit SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
78 :
79 4005 : std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const
80 : {
81 4005 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
82 4005 : ss << zkey;
83 : // ConvertBits requires unsigned char, but CDataStream uses char
84 8010 : std::vector<unsigned char> serkey(ss.begin(), ss.end());
85 8010 : std::vector<unsigned char> data;
86 : // See calculation comment below
87 4005 : data.reserve((serkey.size() * 8 + 4) / 5);
88 1089358 : ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
89 4005 : std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data);
90 4005 : memory_cleanse(serkey.data(), serkey.size());
91 4005 : memory_cleanse(data.data(), data.size());
92 8010 : return ret;
93 : }
94 :
95 0 : std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
96 : };
97 :
98 : namespace KeyIO {
99 :
100 : // Sizes of SaplingPaymentAddress, SaplingExtendedFullViewingKey, and
101 : // SaplingExtendedSpendingKey after ConvertBits<8, 5, true>(). The calculations
102 : // below take the regular serialized size in bytes, convert to bits, and then
103 : // perform ceiling division to get the number of 5-bit clusters.
104 : const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5;
105 : const size_t ConvertedSaplingExtendedFullViewingKeySize = (ZIP32_XFVK_SIZE * 8 + 4) / 5;
106 : const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5;
107 :
108 10211 : std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
109 : {
110 10211 : return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
111 : }
112 :
113 4392 : libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
114 : {
115 8784 : std::vector<unsigned char> data;
116 8784 : auto bech = bech32::Decode(str);
117 4392 : if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
118 4380 : bech.second.size() == ConvertedSaplingPaymentAddressSize) {
119 : // Bech32 decoding
120 4380 : data.reserve((bech.second.size() * 5) / 8);
121 192720 : if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
122 8760 : CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
123 4380 : libzcash::SaplingPaymentAddress ret;
124 4380 : ss >> ret;
125 4380 : return ret;
126 : }
127 : }
128 12 : return libzcash::InvalidEncoding();
129 : }
130 :
131 216 : Optional<libzcash::SaplingPaymentAddress> DecodeSaplingPaymentAddress(const std::string& strAddress)
132 : {
133 216 : libzcash::PaymentAddress addr = KeyIO::DecodePaymentAddress(strAddress);
134 216 : const auto dest = boost::get<libzcash::SaplingPaymentAddress>(&addr);
135 424 : return (dest) ? Optional<libzcash::SaplingPaymentAddress>(*dest) : nullopt;
136 : }
137 :
138 4 : bool IsValidPaymentAddressString(const std::string& str) {
139 4 : return IsValidPaymentAddress(DecodePaymentAddress(str));
140 : }
141 :
142 1003 : std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
143 : {
144 1003 : return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
145 : }
146 :
147 1003 : libzcash::ViewingKey DecodeViewingKey(const std::string& str)
148 : {
149 2006 : auto bech = bech32::Decode(str);
150 1003 : if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK) &&
151 1003 : bech.second.size() == ConvertedSaplingExtendedFullViewingKeySize) {
152 1003 : std::vector<unsigned char> data;
153 : // Bech32 decoding
154 1003 : data.reserve((bech.second.size() * 5) / 8);
155 170510 : if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
156 2006 : CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
157 1003 : libzcash::SaplingExtendedFullViewingKey ret;
158 1003 : ss >> ret;
159 1003 : memory_cleanse(data.data(), data.size());
160 1003 : return ret;
161 : }
162 : }
163 0 : return libzcash::InvalidEncoding();
164 : }
165 :
166 4005 : std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
167 : {
168 4005 : return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
169 : }
170 :
171 3940 : libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
172 : {
173 7880 : std::vector<unsigned char> data;
174 7880 : auto bech = bech32::Decode(str);
175 3940 : if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
176 3007 : bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
177 : // Bech32 decoding
178 3007 : data.reserve((bech.second.size() * 5) / 8);
179 511190 : if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
180 6014 : CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
181 3007 : libzcash::SaplingExtendedSpendingKey ret;
182 3007 : ss >> ret;
183 3007 : memory_cleanse(data.data(), data.size());
184 3007 : return ret;
185 : }
186 : }
187 933 : memory_cleanse(data.data(), data.size());
188 933 : return libzcash::InvalidEncoding();
189 : }
190 :
191 : } // KeyIO namespace
|