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/noteencryption.h"
7 :
8 : #include "sapling/prf.h"
9 : #include "sapling/sapling_util.h"
10 :
11 : #include <librustzcash.h>
12 : #include <sodium.h>
13 :
14 : #include <stdexcept>
15 :
16 : #define NOTEENCRYPTION_CIPHER_KEYSIZE 32
17 :
18 0 : void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES])
19 : {
20 0 : key[0] &= 248;
21 0 : key[31] &= 127;
22 0 : key[31] |= 64;
23 0 : }
24 :
25 1439 : void PRF_ock(
26 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
27 : const uint256 &ovk,
28 : const uint256 &cv,
29 : const uint256 &cm,
30 : const uint256 &epk
31 : )
32 : {
33 1439 : unsigned char block[128] = {};
34 1439 : memcpy(block+0, ovk.begin(), 32);
35 1439 : memcpy(block+32, cv.begin(), 32);
36 1439 : memcpy(block+64, cm.begin(), 32);
37 1439 : memcpy(block+96, epk.begin(), 32);
38 :
39 1439 : unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
40 1439 : memcpy(personalization, "Zcash_Derive_ock", 16);
41 :
42 1439 : if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE,
43 : block, 128,
44 : nullptr, 0, // No key.
45 : nullptr, // No salt.
46 : personalization
47 : ) != 0)
48 : {
49 0 : throw std::logic_error("hash function failure");
50 : }
51 1439 : }
52 :
53 10335 : void KDF_Sapling(
54 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
55 : const uint256 &dhsecret,
56 : const uint256 &epk
57 : )
58 : {
59 10335 : unsigned char block[64] = {};
60 10335 : memcpy(block+0, dhsecret.begin(), 32);
61 10335 : memcpy(block+32, epk.begin(), 32);
62 :
63 10335 : unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
64 10335 : memcpy(personalization, "Zcash_SaplingKDF", 16);
65 :
66 10335 : if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE,
67 : block, 64,
68 : nullptr, 0, // No key.
69 : nullptr, // No salt.
70 : personalization
71 : ) != 0)
72 : {
73 0 : throw std::logic_error("hash function failure");
74 : }
75 10335 : }
76 :
77 0 : void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
78 : const uint256 &dhsecret,
79 : const uint256 &epk,
80 : const uint256 &pk_enc,
81 : const uint256 &hSig,
82 : unsigned char nonce
83 : )
84 : {
85 0 : if (nonce == 0xff) {
86 0 : throw std::logic_error("no additional nonce space for KDF");
87 : }
88 :
89 0 : unsigned char block[128] = {};
90 0 : memcpy(block+0, hSig.begin(), 32);
91 0 : memcpy(block+32, dhsecret.begin(), 32);
92 0 : memcpy(block+64, epk.begin(), 32);
93 0 : memcpy(block+96, pk_enc.begin(), 32);
94 :
95 0 : unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
96 0 : memcpy(personalization, "ZcashKDF", 8);
97 0 : memcpy(personalization+8, &nonce, 1);
98 :
99 0 : if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE,
100 : block, 128,
101 : nullptr, 0, // No key.
102 : nullptr, // No salt.
103 : personalization
104 : ) != 0)
105 : {
106 0 : throw std::logic_error("hash function failure");
107 : }
108 0 : }
109 :
110 : namespace libzcash {
111 :
112 1328 : Optional<SaplingNoteEncryption> SaplingNoteEncryption::FromDiversifier(diversifier_t d) {
113 1328 : uint256 epk;
114 1328 : uint256 esk;
115 :
116 : // Pick random esk
117 1328 : librustzcash_sapling_generate_r(esk.begin());
118 :
119 : // Compute epk given the diversifier
120 1328 : if (!librustzcash_sapling_ka_derivepublic(d.begin(), esk.begin(), epk.begin())) {
121 1 : return nullopt;
122 : }
123 :
124 1327 : return SaplingNoteEncryption(epk, esk);
125 : }
126 :
127 1328 : Optional<SaplingEncCiphertext> SaplingNoteEncryption::encrypt_to_recipient(
128 : const uint256 &pk_d,
129 : const SaplingEncPlaintext &message
130 : )
131 : {
132 1328 : if (already_encrypted_enc) {
133 1 : throw std::logic_error("already encrypted to the recipient using this key");
134 : }
135 :
136 1327 : uint256 dhsecret;
137 :
138 1327 : if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
139 0 : return nullopt;
140 : }
141 :
142 : // Construct the symmetric key
143 1327 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
144 1327 : KDF_Sapling(K, dhsecret, epk);
145 :
146 : // The nonce is zero because we never reuse keys
147 1327 : unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
148 :
149 1327 : SaplingEncCiphertext ciphertext;
150 :
151 1327 : crypto_aead_chacha20poly1305_ietf_encrypt(
152 : ciphertext.begin(), nullptr,
153 : message.begin(), ZC_SAPLING_ENCPLAINTEXT_SIZE,
154 : nullptr, 0, // no "additional data"
155 : nullptr, cipher_nonce, K
156 : );
157 :
158 1327 : already_encrypted_enc = true;
159 :
160 1327 : return ciphertext;
161 : }
162 :
163 8911 : Optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
164 : const SaplingEncCiphertext &ciphertext,
165 : const uint256 &ivk,
166 : const uint256 &epk
167 : )
168 : {
169 8911 : uint256 dhsecret;
170 :
171 8911 : if (!librustzcash_sapling_ka_agree(epk.begin(), ivk.begin(), dhsecret.begin())) {
172 0 : return nullopt;
173 : }
174 :
175 : // Construct the symmetric key
176 8911 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
177 8911 : KDF_Sapling(K, dhsecret, epk);
178 :
179 : // The nonce is zero because we never reuse keys
180 8911 : unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
181 :
182 8911 : SaplingEncPlaintext plaintext;
183 :
184 8911 : if (crypto_aead_chacha20poly1305_ietf_decrypt(
185 : plaintext.begin(), nullptr,
186 : nullptr,
187 : ciphertext.begin(), ZC_SAPLING_ENCCIPHERTEXT_SIZE,
188 : nullptr,
189 : 0,
190 : cipher_nonce, K) != 0)
191 : {
192 4765 : return nullopt;
193 : }
194 :
195 4146 : return plaintext;
196 : }
197 :
198 97 : Optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
199 : const SaplingEncCiphertext &ciphertext,
200 : const uint256 &epk,
201 : const uint256 &esk,
202 : const uint256 &pk_d
203 : )
204 : {
205 97 : uint256 dhsecret;
206 :
207 97 : if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
208 0 : return nullopt;
209 : }
210 :
211 : // Construct the symmetric key
212 97 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
213 97 : KDF_Sapling(K, dhsecret, epk);
214 :
215 : // The nonce is zero because we never reuse keys
216 97 : unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
217 :
218 97 : SaplingEncPlaintext plaintext;
219 :
220 97 : if (crypto_aead_chacha20poly1305_ietf_decrypt(
221 : plaintext.begin(), nullptr,
222 : nullptr,
223 : ciphertext.begin(), ZC_SAPLING_ENCCIPHERTEXT_SIZE,
224 : nullptr,
225 : 0,
226 : cipher_nonce, K) != 0)
227 : {
228 0 : return nullopt;
229 : }
230 :
231 97 : return plaintext;
232 : }
233 :
234 :
235 1328 : SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves(
236 : const uint256 &ovk,
237 : const uint256 &cv,
238 : const uint256 &cm,
239 : const SaplingOutPlaintext &message
240 : )
241 : {
242 1328 : if (already_encrypted_out) {
243 1 : throw std::logic_error("already encrypted to the recipient using this key");
244 : }
245 :
246 : // Construct the symmetric key
247 1327 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
248 1327 : PRF_ock(K, ovk, cv, cm, epk);
249 :
250 : // The nonce is zero because we never reuse keys
251 1327 : unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
252 :
253 1327 : SaplingOutCiphertext ciphertext;
254 :
255 1327 : crypto_aead_chacha20poly1305_ietf_encrypt(
256 : ciphertext.begin(), nullptr,
257 : message.begin(), ZC_SAPLING_OUTPLAINTEXT_SIZE,
258 : nullptr, 0, // no "additional data"
259 : nullptr, cipher_nonce, K
260 : );
261 :
262 1327 : already_encrypted_out = true;
263 :
264 1327 : return ciphertext;
265 : }
266 :
267 112 : Optional<SaplingOutPlaintext> AttemptSaplingOutDecryption(
268 : const SaplingOutCiphertext &ciphertext,
269 : const uint256 &ovk,
270 : const uint256 &cv,
271 : const uint256 &cm,
272 : const uint256 &epk
273 : )
274 : {
275 : // Construct the symmetric key
276 112 : unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
277 112 : PRF_ock(K, ovk, cv, cm, epk);
278 :
279 : // The nonce is zero because we never reuse keys
280 112 : unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
281 :
282 112 : SaplingOutPlaintext plaintext;
283 :
284 112 : if (crypto_aead_chacha20poly1305_ietf_decrypt(
285 : plaintext.begin(), nullptr,
286 : nullptr,
287 : ciphertext.begin(), ZC_SAPLING_OUTCIPHERTEXT_SIZE,
288 : nullptr,
289 : 0,
290 : cipher_nonce, K) != 0)
291 : {
292 13 : return nullopt;
293 : }
294 :
295 99 : return plaintext;
296 : }
297 :
298 : }
|