Line data Source code
1 : // Copyright (c) 2016-2020 The ZCash developers
2 : // Copyright (c) 2021 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "sapling/note.h"
7 :
8 : #include "crypto/sha256.h"
9 : #include "random.h"
10 : #include "sapling/prf.h"
11 : #include "sapling/sapling_util.h"
12 : #include "streams.h"
13 : #include "version.h"
14 :
15 : #include <librustzcash.h>
16 :
17 : using namespace libzcash;
18 :
19 : // Construct and populate Sapling note for a given payment address and value.
20 417 : SaplingNote::SaplingNote(const SaplingPaymentAddress& address, const uint64_t value) :
21 417 : BaseNote(value)
22 : {
23 417 : d = address.d;
24 417 : pk_d = address.pk_d;
25 417 : librustzcash_sapling_generate_r(r.begin());
26 417 : }
27 :
28 : // Call librustzcash to compute the commitment
29 744 : Optional<uint256> SaplingNote::cmu() const
30 : {
31 744 : uint256 result;
32 744 : if (!librustzcash_sapling_compute_cm(
33 : d.data(),
34 : pk_d.begin(),
35 : value(),
36 : r.begin(),
37 : result.begin()
38 : ))
39 : {
40 0 : return nullopt;
41 : }
42 :
43 744 : return result;
44 : }
45 :
46 : // Call librustzcash to compute the nullifier
47 363 : Optional<uint256> SaplingNote::nullifier(const SaplingFullViewingKey& vk, const uint64_t position) const
48 : {
49 363 : auto ak = vk.ak;
50 363 : auto nk = vk.nk;
51 :
52 363 : uint256 result;
53 363 : if (!librustzcash_sapling_compute_nf(
54 : d.data(),
55 : pk_d.begin(),
56 : value(),
57 : r.begin(),
58 363 : ak.begin(),
59 363 : nk.begin(),
60 : position,
61 : result.begin()
62 : ))
63 : {
64 0 : return nullopt;
65 : }
66 :
67 363 : return result;
68 : }
69 :
70 : // Construct and populate SaplingNotePlaintext for a given note and memo.
71 328 : SaplingNotePlaintext::SaplingNotePlaintext(
72 : const SaplingNote& note,
73 328 : const std::array<unsigned char, ZC_MEMO_SIZE>& memo) : BaseNotePlaintext(note, memo)
74 : {
75 328 : d = note.d;
76 328 : rcm = note.r;
77 328 : }
78 :
79 :
80 1827 : Optional<SaplingNote> SaplingNotePlaintext::note(const SaplingIncomingViewingKey& ivk) const
81 : {
82 1827 : auto addr = ivk.address(d);
83 1827 : if (addr) {
84 1827 : return SaplingNote(d, addr.get().pk_d, value_, rcm);
85 : } else {
86 0 : return nullopt;
87 : }
88 : }
89 :
90 110 : Optional<SaplingOutgoingPlaintext> SaplingOutgoingPlaintext::decrypt(
91 : const SaplingOutCiphertext& ciphertext,
92 : const uint256& ovk,
93 : const uint256& cv,
94 : const uint256& cm,
95 : const uint256& epk
96 : )
97 : {
98 220 : auto pt = AttemptSaplingOutDecryption(ciphertext, ovk, cv, cm, epk);
99 110 : if (!pt) {
100 8 : return nullopt;
101 : }
102 :
103 : // Deserialize from the plaintext
104 212 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
105 102 : ss << pt.get();
106 :
107 102 : SaplingOutgoingPlaintext ret;
108 102 : ss >> ret;
109 :
110 102 : assert(ss.size() == 0);
111 :
112 102 : return ret;
113 : }
114 :
115 7778 : Optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
116 : const SaplingEncCiphertext& ciphertext,
117 : const uint256& ivk,
118 : const uint256& epk,
119 : const uint256& cmu
120 : )
121 : {
122 15556 : auto pt = AttemptSaplingEncDecryption(ciphertext, ivk, epk);
123 7778 : if (!pt) {
124 5496 : return nullopt;
125 : }
126 :
127 : // Deserialize from the plaintext
128 10060 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
129 2282 : ss << pt.get();
130 :
131 4564 : SaplingNotePlaintext ret;
132 2282 : ss >> ret;
133 :
134 2282 : assert(ss.size() == 0);
135 :
136 2282 : uint256 pk_d;
137 2282 : if (!librustzcash_ivk_to_pkd(ivk.begin(), ret.d.data(), pk_d.begin())) {
138 0 : return nullopt;
139 : }
140 :
141 2282 : uint256 cmu_expected;
142 2282 : if (!librustzcash_sapling_compute_cm(
143 2282 : ret.d.data(),
144 2282 : pk_d.begin(),
145 : ret.value(),
146 2282 : ret.rcm.begin(),
147 : cmu_expected.begin()
148 : ))
149 : {
150 0 : return nullopt;
151 : }
152 :
153 2282 : if (cmu_expected != cmu) {
154 1 : return nullopt;
155 : }
156 :
157 2282 : return ret;
158 : }
159 :
160 103 : Optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
161 : const SaplingEncCiphertext& ciphertext,
162 : const uint256& epk,
163 : const uint256& esk,
164 : const uint256& pk_d,
165 : const uint256& cmu
166 : )
167 : {
168 206 : auto pt = AttemptSaplingEncDecryption(ciphertext, epk, esk, pk_d);
169 103 : if (!pt) {
170 0 : return nullopt;
171 : }
172 :
173 : // Deserialize from the plaintext
174 206 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
175 103 : ss << pt.get();
176 :
177 206 : SaplingNotePlaintext ret;
178 103 : ss >> ret;
179 :
180 103 : uint256 cmu_expected;
181 103 : if (!librustzcash_sapling_compute_cm(
182 103 : ret.d.data(),
183 : pk_d.begin(),
184 : ret.value(),
185 103 : ret.rcm.begin(),
186 : cmu_expected.begin()
187 : ))
188 : {
189 0 : return nullopt;
190 : }
191 :
192 103 : if (cmu_expected != cmu) {
193 1 : return nullopt;
194 : }
195 :
196 102 : assert(ss.size() == 0);
197 :
198 103 : return ret;
199 : }
200 :
201 328 : Optional<SaplingNotePlaintextEncryptionResult> SaplingNotePlaintext::encrypt(const uint256& pk_d) const
202 : {
203 : // Get the encryptor
204 656 : auto sne = SaplingNoteEncryption::FromDiversifier(d);
205 328 : if (!sne) {
206 0 : return nullopt;
207 : }
208 328 : auto enc = sne.get();
209 :
210 : // Create the plaintext
211 656 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
212 328 : ss << (*this);
213 328 : SaplingEncPlaintext pt;
214 328 : assert(pt.size() == ss.size());
215 328 : memcpy(&pt[0], &ss[0], pt.size());
216 :
217 : // Encrypt the plaintext
218 656 : auto encciphertext = enc.encrypt_to_recipient(pk_d, pt);
219 328 : if (!encciphertext) {
220 0 : return nullopt;
221 : }
222 328 : return SaplingNotePlaintextEncryptionResult(encciphertext.get(), enc);
223 : }
224 :
225 :
226 328 : SaplingOutCiphertext SaplingOutgoingPlaintext::encrypt(
227 : const uint256& ovk,
228 : const uint256& cv,
229 : const uint256& cm,
230 : SaplingNoteEncryption& enc
231 : ) const
232 : {
233 : // Create the plaintext
234 328 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
235 328 : ss << (*this);
236 328 : SaplingOutPlaintext pt;
237 328 : assert(pt.size() == ss.size());
238 328 : memcpy(&pt[0], &ss[0], pt.size());
239 :
240 656 : return enc.encrypt_to_ourselves(ovk, cv, cm, pt);
241 : }
|