PIVX Core  5.6.99
P2P Digital Currency
noteencryption.cpp
Go to the documentation of this file.
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 
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 void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES])
19 {
20  key[0] &= 248;
21  key[31] &= 127;
22  key[31] |= 64;
23 }
24 
25 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  unsigned char block[128] = {};
34  memcpy(block+0, ovk.begin(), 32);
35  memcpy(block+32, cv.begin(), 32);
36  memcpy(block+64, cm.begin(), 32);
37  memcpy(block+96, epk.begin(), 32);
38 
39  unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
40  memcpy(personalization, "Zcash_Derive_ock", 16);
41 
42  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  throw std::logic_error("hash function failure");
50  }
51 }
52 
54  unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
55  const uint256 &dhsecret,
56  const uint256 &epk
57 )
58 {
59  unsigned char block[64] = {};
60  memcpy(block+0, dhsecret.begin(), 32);
61  memcpy(block+32, epk.begin(), 32);
62 
63  unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
64  memcpy(personalization, "Zcash_SaplingKDF", 16);
65 
66  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  throw std::logic_error("hash function failure");
74  }
75 }
76 
77 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  if (nonce == 0xff) {
86  throw std::logic_error("no additional nonce space for KDF");
87  }
88 
89  unsigned char block[128] = {};
90  memcpy(block+0, hSig.begin(), 32);
91  memcpy(block+32, dhsecret.begin(), 32);
92  memcpy(block+64, epk.begin(), 32);
93  memcpy(block+96, pk_enc.begin(), 32);
94 
95  unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
96  memcpy(personalization, "ZcashKDF", 8);
97  memcpy(personalization+8, &nonce, 1);
98 
99  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  throw std::logic_error("hash function failure");
107  }
108 }
109 
110 namespace libzcash {
111 
113  uint256 epk;
114  uint256 esk;
115 
116  // Pick random esk
118 
119  // Compute epk given the diversifier
120  if (!librustzcash_sapling_ka_derivepublic(d.begin(), esk.begin(), epk.begin())) {
121  return nullopt;
122  }
123 
124  return SaplingNoteEncryption(epk, esk);
125 }
126 
128  const uint256 &pk_d,
129  const SaplingEncPlaintext &message
130 )
131 {
132  if (already_encrypted_enc) {
133  throw std::logic_error("already encrypted to the recipient using this key");
134  }
135 
136  uint256 dhsecret;
137 
138  if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
139  return nullopt;
140  }
141 
142  // Construct the symmetric key
143  unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
144  KDF_Sapling(K, dhsecret, epk);
145 
146  // The nonce is zero because we never reuse keys
147  unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
148 
149  SaplingEncCiphertext ciphertext;
150 
151  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  already_encrypted_enc = true;
159 
160  return ciphertext;
161 }
162 
164  const SaplingEncCiphertext &ciphertext,
165  const uint256 &ivk,
166  const uint256 &epk
167 )
168 {
169  uint256 dhsecret;
170 
171  if (!librustzcash_sapling_ka_agree(epk.begin(), ivk.begin(), dhsecret.begin())) {
172  return nullopt;
173  }
174 
175  // Construct the symmetric key
176  unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
177  KDF_Sapling(K, dhsecret, epk);
178 
179  // The nonce is zero because we never reuse keys
180  unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
181 
182  SaplingEncPlaintext plaintext;
183 
184  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  return nullopt;
193  }
194 
195  return plaintext;
196 }
197 
199  const SaplingEncCiphertext &ciphertext,
200  const uint256 &epk,
201  const uint256 &esk,
202  const uint256 &pk_d
203 )
204 {
205  uint256 dhsecret;
206 
207  if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
208  return nullopt;
209  }
210 
211  // Construct the symmetric key
212  unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
213  KDF_Sapling(K, dhsecret, epk);
214 
215  // The nonce is zero because we never reuse keys
216  unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
217 
218  SaplingEncPlaintext plaintext;
219 
220  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  return nullopt;
229  }
230 
231  return plaintext;
232 }
233 
234 
236  const uint256 &ovk,
237  const uint256 &cv,
238  const uint256 &cm,
239  const SaplingOutPlaintext &message
240 )
241 {
242  if (already_encrypted_out) {
243  throw std::logic_error("already encrypted to the recipient using this key");
244  }
245 
246  // Construct the symmetric key
247  unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
248  PRF_ock(K, ovk, cv, cm, epk);
249 
250  // The nonce is zero because we never reuse keys
251  unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
252 
253  SaplingOutCiphertext ciphertext;
254 
255  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  already_encrypted_out = true;
263 
264  return ciphertext;
265 }
266 
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  unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
277  PRF_ock(K, ovk, cv, cm, epk);
278 
279  // The nonce is zero because we never reuse keys
280  unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
281 
282  SaplingOutPlaintext plaintext;
283 
284  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  return nullopt;
293  }
294 
295  return plaintext;
296 }
297 
298 }
unsigned char * begin()
Definition: uint256.h:63
SaplingOutCiphertext encrypt_to_ourselves(const uint256 &ovk, const uint256 &cv, const uint256 &cm, const SaplingOutPlaintext &message)
static Optional< SaplingNoteEncryption > FromDiversifier(diversifier_t d)
SaplingNoteEncryption(uint256 epk, uint256 esk)
Optional< SaplingEncCiphertext > encrypt_to_recipient(const uint256 &pk_d, const SaplingEncPlaintext &message)
256-bit opaque blob.
Definition: uint256.h:138
void * memcpy(void *a, const void *b, size_t c)
bool librustzcash_sapling_ka_agree(const unsigned char *p, const unsigned char *sk, unsigned char *result)
Compute [sk] [8] P for some 32-byte point P, and 32-byte Fs.
bool librustzcash_sapling_ka_derivepublic(const unsigned char *diversifier, const unsigned char *esk, unsigned char *result)
Compute g_d = GH(diversifier) and returns false if the diversifier is invalid.
void librustzcash_sapling_generate_r(unsigned char *result)
Generate uniformly random scalar in Jubjub.
unsigned int nonce
Definition: miner_tests.cpp:28
std::array< unsigned char, ZC_SAPLING_ENCPLAINTEXT_SIZE > SaplingEncPlaintext
Optional< SaplingEncPlaintext > AttemptSaplingEncDecryption(const SaplingEncCiphertext &ciphertext, const uint256 &ivk, const uint256 &epk)
std::array< unsigned char, ZC_SAPLING_OUTPLAINTEXT_SIZE > SaplingOutPlaintext
std::array< unsigned char, ZC_SAPLING_ENCCIPHERTEXT_SIZE > SaplingEncCiphertext
Optional< SaplingOutPlaintext > AttemptSaplingOutDecryption(const SaplingOutCiphertext &ciphertext, const uint256 &ovk, const uint256 &cv, const uint256 &cm, const uint256 &epk)
std::array< unsigned char, ZC_SAPLING_OUTCIPHERTEXT_SIZE > SaplingOutCiphertext
#define NOTEENCRYPTION_CIPHER_KEYSIZE
void KDF_Sapling(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], const uint256 &dhsecret, const uint256 &epk)
void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], const uint256 &dhsecret, const uint256 &epk, const uint256 &pk_enc, const uint256 &hSig, unsigned char nonce)
void PRF_ock(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], const uint256 &ovk, const uint256 &cv, const uint256 &cm, const uint256 &epk)
void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES])
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
#define ZC_SAPLING_ENCPLAINTEXT_SIZE
Definition: sapling.h:31
std::array< unsigned char, ZC_DIVERSIFIER_SIZE > diversifier_t
Definition: sapling.h:38
#define ZC_SAPLING_ENCCIPHERTEXT_SIZE
Definition: sapling.h:34
#define ZC_SAPLING_OUTPLAINTEXT_SIZE
Definition: sapling.h:32
#define ZC_SAPLING_OUTCIPHERTEXT_SIZE
Definition: sapling.h:35