PIVX Core  5.6.99
P2P Digital Currency
noteencryption_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2016-2020 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 "test/test_pivx.h"
7 
8 #include <array>
9 #include <stdexcept>
10 
11 #include "crypto/sha256.h"
12 #include "sapling/address.h"
13 #include "sapling/note.h"
14 #include "sapling/noteencryption.h"
15 #include "sapling/prf.h"
16 #include "sapling/sapling_util.h"
17 
18 #include <boost/test/unit_test.hpp>
19 #include <librustzcash.h>
20 #include <sodium.h>
21 
22 BOOST_FIXTURE_TEST_SUITE(noteencryption_tests, BasicTestingSetup)
23 
24 BOOST_AUTO_TEST_CASE(note_plain_text_test)
25 {
27  auto fvk = xsk.full_viewing_key();
28  auto ivk = fvk.in_viewing_key();
29  libzcash::SaplingPaymentAddress addr = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
30 
31  std::array<unsigned char, ZC_MEMO_SIZE> memo;
32  for (size_t i = 0; i < ZC_MEMO_SIZE; i++) {
33  // Fill the message with dummy data
34  memo[i] = (unsigned char) i;
35  }
36 
37  libzcash::SaplingNote note(addr, 39393);
38  auto cmu_opt = note.cmu();
39  if (!cmu_opt) {
40  BOOST_ERROR("SaplingNote cm failed");
41  }
42  uint256 cmu = cmu_opt.get();
43  libzcash::SaplingNotePlaintext pt(note, memo);
44 
45  auto res = pt.encrypt(addr.pk_d);
46  if (!res) {
47  BOOST_ERROR("SaplingNotePlaintext encrypt failed");
48  }
49 
50  auto enc = res.get();
51 
52  auto ct = enc.first;
53  auto encryptor = enc.second;
54  auto epk = encryptor.get_epk();
55 
56  // Try to decrypt with incorrect commitment
58  ct,
59  ivk,
60  epk,
61  uint256()
62  ));
63 
64  // Try to decrypt with correct commitment
66  ct,
67  ivk,
68  epk,
69  cmu
70  );
71 
72  if (!foo) {
73  BOOST_ERROR("SaplingNotePlaintext decrypt failed");
74  }
75 
76  auto bar = foo.get();
77 
78  BOOST_CHECK(bar.value() == pt.value());
79  BOOST_CHECK(bar.memo() == pt.memo());
80  BOOST_CHECK(bar.d == pt.d);
81  BOOST_CHECK(bar.rcm == pt.rcm);
82 
83  auto foobar = bar.note(ivk);
84 
85  if (!foobar) {
86  // Improve this message
87  BOOST_ERROR("Invalid note");
88  }
89 
90  auto new_note = foobar.get();
91 
92  BOOST_CHECK(note.value() == new_note.value());
93  BOOST_CHECK(note.d == new_note.d);
94  BOOST_CHECK(note.pk_d == new_note.pk_d);
95  BOOST_CHECK(note.r == new_note.r);
96  BOOST_CHECK(note.cmu() == new_note.cmu());
97 
99  out_pt.pk_d = note.pk_d;
100  out_pt.esk = encryptor.get_esk();
101 
102  auto ovk = random_uint256();
103  auto cv = random_uint256();
104  auto cm = random_uint256();
105 
106  auto out_ct = out_pt.encrypt(
107  ovk,
108  cv,
109  cm,
110  encryptor
111  );
112 
113  auto decrypted_out_ct = out_pt.decrypt(
114  out_ct,
115  ovk,
116  cv,
117  cm,
118  encryptor.get_epk()
119  );
120 
121  if (!decrypted_out_ct) {
122  BOOST_ERROR("SaplingOutgoingPlaintext decrypt failed");
123  }
124 
125  auto decrypted_out_ct_unwrapped = decrypted_out_ct.get();
126 
127  BOOST_CHECK(decrypted_out_ct_unwrapped.pk_d == out_pt.pk_d);
128  BOOST_CHECK(decrypted_out_ct_unwrapped.esk == out_pt.esk);
129 
130  // Test sender won't accept invalid commitments
132  ct,
133  epk,
134  decrypted_out_ct_unwrapped.esk,
135  decrypted_out_ct_unwrapped.pk_d,
136  uint256()
137  ));
138 
139  // Test sender can decrypt the note ciphertext.
141  ct,
142  epk,
143  decrypted_out_ct_unwrapped.esk,
144  decrypted_out_ct_unwrapped.pk_d,
145  cmu
146  );
147 
148  if (!foo) {
149  BOOST_ERROR("Sender decrypt note ciphertext failed.");
150  }
151 
152  bar = foo.get();
153 
154  BOOST_CHECK(bar.value() == pt.value());
155  BOOST_CHECK(bar.memo() == pt.memo());
156  BOOST_CHECK(bar.d == pt.d);
157  BOOST_CHECK(bar.rcm == pt.rcm);
158 }
159 
160 BOOST_AUTO_TEST_CASE(SaplingApi_test)
161 {
162  // Create recipient addresses
164  auto vk = sk.full_viewing_key();
165  auto ivk = vk.in_viewing_key();
166  libzcash::SaplingPaymentAddress pk_1 = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
167  libzcash::SaplingPaymentAddress pk_2 = *ivk.address({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
168 
169  // Blob of stuff we're encrypting
170  std::array<unsigned char, ZC_SAPLING_ENCPLAINTEXT_SIZE> message;
171  for (size_t i = 0; i < ZC_SAPLING_ENCPLAINTEXT_SIZE; i++) {
172  // Fill the message with dummy data
173  message[i] = (unsigned char) i;
174  }
175 
176  std::array<unsigned char, ZC_SAPLING_OUTPLAINTEXT_SIZE> small_message;
177  for (size_t i = 0; i < ZC_SAPLING_OUTPLAINTEXT_SIZE; i++) {
178  // Fill the message with dummy data
179  small_message[i] = (unsigned char) i;
180  }
181 
182  // Invalid diversifier
183  BOOST_CHECK(boost::none == libzcash::SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
184 
185  // Encrypt to pk_1
187  auto ciphertext_1 = *enc.encrypt_to_recipient(
188  pk_1.pk_d,
189  message
190  );
191  auto epk_1 = enc.get_epk();
192  {
193  uint256 test_epk;
194  uint256 test_esk = enc.get_esk();
195  BOOST_CHECK(librustzcash_sapling_ka_derivepublic(pk_1.d.begin(), test_esk.begin(), test_epk.begin()));
196  BOOST_CHECK(test_epk == epk_1);
197  }
198  auto cv_1 = random_uint256();
199  auto cm_1 = random_uint256();
200  auto out_ciphertext_1 = enc.encrypt_to_ourselves(
201  sk.ovk,
202  cv_1,
203  cm_1,
204  small_message
205  );
206 
207  // Encrypt to pk_2
209  auto ciphertext_2 = *enc.encrypt_to_recipient(
210  pk_2.pk_d,
211  message
212  );
213  auto epk_2 = enc.get_epk();
214 
215  auto cv_2 = random_uint256();
216  auto cm_2 = random_uint256();
217  auto out_ciphertext_2 = enc.encrypt_to_ourselves(
218  sk.ovk,
219  cv_2,
220  cm_2,
221  small_message
222  );
223 
224  // Test nonce-reuse resistance of API
225  {
227 
228  tmp_enc.encrypt_to_recipient(
229  pk_1.pk_d,
230  message
231  );
232 
233  BOOST_CHECK_THROW(tmp_enc.encrypt_to_recipient(
234  pk_1.pk_d,
235  message
236  ), std::logic_error);
237 
238  tmp_enc.encrypt_to_ourselves(
239  sk.ovk,
240  cv_2,
241  cm_2,
242  small_message
243  );
244 
245  BOOST_CHECK_THROW(tmp_enc.encrypt_to_ourselves(
246  sk.ovk,
247  cv_2,
248  cm_2,
249  small_message
250  ), std::logic_error);
251  }
252 
253  // Try to decrypt
254  auto plaintext_1 = *AttemptSaplingEncDecryption(
255  ciphertext_1,
256  ivk,
257  epk_1
258  );
259  BOOST_CHECK(message == plaintext_1);
260 
261  auto small_plaintext_1 = *libzcash::AttemptSaplingOutDecryption(
262  out_ciphertext_1,
263  sk.ovk,
264  cv_1,
265  cm_1,
266  epk_1
267  );
268  BOOST_CHECK(small_message == small_plaintext_1);
269 
270  auto plaintext_2 = *AttemptSaplingEncDecryption(
271  ciphertext_2,
272  ivk,
273  epk_2
274  );
275  BOOST_CHECK(message == plaintext_2);
276 
277  auto small_plaintext_2 = *libzcash::AttemptSaplingOutDecryption(
278  out_ciphertext_2,
279  sk.ovk,
280  cv_2,
281  cm_2,
282  epk_2
283  );
284  BOOST_CHECK(small_message == small_plaintext_2);
285 
286  // Try to decrypt out ciphertext with wrong key material
288  out_ciphertext_1,
289  random_uint256(),
290  cv_1,
291  cm_1,
292  epk_1
293  ));
295  out_ciphertext_1,
296  sk.ovk,
297  random_uint256(),
298  cm_1,
299  epk_1
300  ));
302  out_ciphertext_1,
303  sk.ovk,
304  cv_1,
305  random_uint256(),
306  epk_1
307  ));
309  out_ciphertext_1,
310  sk.ovk,
311  cv_1,
312  cm_1,
314  ));
315 
316  // Try to decrypt with wrong ephemeral key
318  ciphertext_1,
319  ivk,
320  epk_2
321  ));
323  ciphertext_2,
324  ivk,
325  epk_1
326  ));
327 
328  // Try to decrypt with wrong ivk
330  ciphertext_1,
331  uint256(),
332  epk_1
333  ));
335  ciphertext_2,
336  uint256(),
337  epk_2
338  ));
339 }
340 
unsigned char * begin()
Definition: uint256.h:63
uint64_t value() const
Definition: note.h:30
const std::array< unsigned char, ZC_MEMO_SIZE > & memo() const
Definition: note.h:66
uint64_t value() const
Definition: note.h:65
SaplingFullViewingKey full_viewing_key() const
Definition: address.cpp:29
SaplingIncomingViewingKey in_viewing_key() const
Definition: address.cpp:45
static Optional< SaplingNoteEncryption > FromDiversifier(diversifier_t d)
Optional< uint256 > cmu() const
Definition: note.cpp:29
diversifier_t d
Definition: note.h:35
uint256 pk_d
Definition: note.h:36
Optional< SaplingNotePlaintextEncryptionResult > encrypt(const uint256 &pk_d) const
Definition: note.cpp:201
static Optional< SaplingNotePlaintext > decrypt(const SaplingEncCiphertext &ciphertext, const uint256 &ivk, const uint256 &epk, const uint256 &cmu)
Definition: note.cpp:115
SaplingOutCiphertext encrypt(const uint256 &ovk, const uint256 &cv, const uint256 &cm, SaplingNoteEncryption &enc) const
Definition: note.cpp:226
static Optional< SaplingOutgoingPlaintext > decrypt(const SaplingOutCiphertext &ciphertext, const uint256 &ovk, const uint256 &cv, const uint256 &cm, const uint256 &epk)
Definition: note.cpp:90
Sapling functions.
Definition: address.h:30
SaplingExpandedSpendingKey expanded_spending_key() const
Definition: address.cpp:37
256-bit opaque blob.
Definition: uint256.h:138
BOOST_AUTO_TEST_SUITE_END()
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.
Optional< SaplingEncPlaintext > AttemptSaplingEncDecryption(const SaplingEncCiphertext &ciphertext, const uint256 &ivk, const uint256 &epk)
Optional< SaplingOutPlaintext > AttemptSaplingOutDecryption(const SaplingOutCiphertext &ciphertext, const uint256 &ovk, const uint256 &cv, const uint256 &cm, const uint256 &epk)
BOOST_AUTO_TEST_CASE(note_plain_text_test)
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition: object.cpp:19
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK(expr)
Definition: object.cpp:17
#define ZC_SAPLING_ENCPLAINTEXT_SIZE
Definition: sapling.h:31
#define ZC_SAPLING_OUTPLAINTEXT_SIZE
Definition: sapling.h:32
#define ZC_MEMO_SIZE
Definition: sapling.h:24
uint256 random_uint256()
Basic testing setup.
Definition: test_pivx.h:51