LCOV - code coverage report
Current view: top level - src/test/librust - noteencryption_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 121 127 95.3 %
Date: 2025-04-02 01:23:23 Functions: 4 4 100.0 %

          Line data    Source code
       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           2 : BOOST_AUTO_TEST_CASE(note_plain_text_test)
      25             : {
      26           2 :     auto xsk = libzcash::SaplingSpendingKey(uint256()).expanded_spending_key();
      27           1 :     auto fvk = xsk.full_viewing_key();
      28           1 :     auto ivk = fvk.in_viewing_key();
      29           2 :     libzcash::SaplingPaymentAddress addr = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
      30             : 
      31           1 :     std::array<unsigned char, ZC_MEMO_SIZE> memo;
      32         513 :     for (size_t i = 0; i < ZC_MEMO_SIZE; i++) {
      33             :         // Fill the message with dummy data
      34         512 :         memo[i] = (unsigned char) i;
      35             :     }
      36             : 
      37           1 :     libzcash::SaplingNote note(addr, 39393);
      38           1 :     auto cmu_opt = note.cmu();
      39           1 :     if (!cmu_opt) {
      40           0 :         BOOST_ERROR("SaplingNote cm failed");
      41             :     }
      42           1 :     uint256 cmu = cmu_opt.get();
      43           1 :     libzcash::SaplingNotePlaintext pt(note, memo);
      44             : 
      45           1 :     auto res = pt.encrypt(addr.pk_d);
      46           1 :     if (!res) {
      47           0 :         BOOST_ERROR("SaplingNotePlaintext encrypt failed");
      48             :     }
      49             : 
      50           1 :     auto enc = res.get();
      51             : 
      52           1 :     auto ct = enc.first;
      53           1 :     auto encryptor = enc.second;
      54           1 :     auto epk = encryptor.get_epk();
      55             : 
      56             :     // Try to decrypt with incorrect commitment
      57           3 :     BOOST_CHECK(!libzcash::SaplingNotePlaintext::decrypt(
      58             :         ct,
      59             :         ivk,
      60             :         epk,
      61             :         uint256()
      62             :     ));
      63             : 
      64             :     // Try to decrypt with correct commitment
      65           1 :     auto foo = libzcash::SaplingNotePlaintext::decrypt(
      66             :         ct,
      67             :         ivk,
      68             :         epk,
      69             :         cmu
      70           1 :     );
      71             : 
      72           1 :     if (!foo) {
      73           0 :         BOOST_ERROR("SaplingNotePlaintext decrypt failed");
      74             :     }
      75             : 
      76           1 :     auto bar = foo.get();
      77             : 
      78           2 :     BOOST_CHECK(bar.value() == pt.value());
      79           2 :     BOOST_CHECK(bar.memo() == pt.memo());
      80           2 :     BOOST_CHECK(bar.d == pt.d);
      81           2 :     BOOST_CHECK(bar.rcm == pt.rcm);
      82             : 
      83           1 :     auto foobar = bar.note(ivk);
      84             : 
      85           1 :     if (!foobar) {
      86             :         // Improve this message
      87           0 :         BOOST_ERROR("Invalid note");
      88             :     }
      89             : 
      90           2 :     auto new_note = foobar.get();
      91             : 
      92           2 :     BOOST_CHECK(note.value() == new_note.value());
      93           2 :     BOOST_CHECK(note.d == new_note.d);
      94           2 :     BOOST_CHECK(note.pk_d == new_note.pk_d);
      95           2 :     BOOST_CHECK(note.r == new_note.r);
      96           2 :     BOOST_CHECK(note.cmu() == new_note.cmu());
      97             : 
      98           1 :     libzcash::SaplingOutgoingPlaintext out_pt;
      99           1 :     out_pt.pk_d = note.pk_d;
     100           1 :     out_pt.esk = encryptor.get_esk();
     101             : 
     102           1 :     auto ovk = random_uint256();
     103           1 :     auto cv = random_uint256();
     104           1 :     auto cm = random_uint256();
     105             : 
     106           1 :     auto out_ct = out_pt.encrypt(
     107             :         ovk,
     108             :         cv,
     109             :         cm,
     110             :         encryptor
     111           1 :     );
     112             : 
     113           1 :     auto decrypted_out_ct = out_pt.decrypt(
     114             :         out_ct,
     115             :         ovk,
     116             :         cv,
     117             :         cm,
     118           2 :         encryptor.get_epk()
     119           2 :     );
     120             : 
     121           1 :     if (!decrypted_out_ct) {
     122           0 :         BOOST_ERROR("SaplingOutgoingPlaintext decrypt failed");
     123             :     }
     124             : 
     125           1 :     auto decrypted_out_ct_unwrapped = decrypted_out_ct.get();
     126             : 
     127           2 :     BOOST_CHECK(decrypted_out_ct_unwrapped.pk_d == out_pt.pk_d);
     128           2 :     BOOST_CHECK(decrypted_out_ct_unwrapped.esk == out_pt.esk);
     129             : 
     130             :     // Test sender won't accept invalid commitments
     131           3 :     BOOST_CHECK(!libzcash::SaplingNotePlaintext::decrypt(
     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.
     140           1 :     foo = libzcash::SaplingNotePlaintext::decrypt(
     141             :         ct,
     142             :         epk,
     143             :         decrypted_out_ct_unwrapped.esk,
     144             :         decrypted_out_ct_unwrapped.pk_d,
     145             :         cmu
     146           1 :     );
     147             : 
     148           1 :     if (!foo) {
     149           0 :         BOOST_ERROR("Sender decrypt note ciphertext failed.");
     150             :     }
     151             : 
     152           1 :     bar = foo.get();
     153             : 
     154           2 :     BOOST_CHECK(bar.value() == pt.value());
     155           2 :     BOOST_CHECK(bar.memo() == pt.memo());
     156           2 :     BOOST_CHECK(bar.d == pt.d);
     157           2 :     BOOST_CHECK(bar.rcm == pt.rcm);
     158           1 : }
     159             : 
     160           2 : BOOST_AUTO_TEST_CASE(SaplingApi_test)
     161             : {
     162             :     // Create recipient addresses
     163           2 :     auto sk = libzcash::SaplingSpendingKey(uint256()).expanded_spending_key();
     164           1 :     auto vk = sk.full_viewing_key();
     165           1 :     auto ivk = vk.in_viewing_key();
     166           2 :     libzcash::SaplingPaymentAddress pk_1 = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
     167           2 :     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           1 :     std::array<unsigned char, ZC_SAPLING_ENCPLAINTEXT_SIZE> message;
     171         565 :     for (size_t i = 0; i < ZC_SAPLING_ENCPLAINTEXT_SIZE; i++) {
     172             :     // Fill the message with dummy data
     173         564 :     message[i] = (unsigned char) i;
     174             :     }
     175             : 
     176             :     std::array<unsigned char, ZC_SAPLING_OUTPLAINTEXT_SIZE> small_message;
     177          65 :     for (size_t i = 0; i < ZC_SAPLING_OUTPLAINTEXT_SIZE; i++) {
     178             :     // Fill the message with dummy data
     179          64 :     small_message[i] = (unsigned char) i;
     180             :     }
     181             : 
     182             :     // Invalid diversifier
     183           2 :     BOOST_CHECK(boost::none == libzcash::SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
     184             : 
     185             :     // Encrypt to pk_1
     186           2 :     auto enc = *libzcash::SaplingNoteEncryption::FromDiversifier(pk_1.d);
     187           1 :     auto ciphertext_1 = *enc.encrypt_to_recipient(
     188             :             pk_1.pk_d,
     189             :             message
     190           1 :     );
     191           1 :     auto epk_1 = enc.get_epk();
     192           1 :     {
     193           1 :         uint256 test_epk;
     194           1 :         uint256 test_esk = enc.get_esk();
     195           2 :         BOOST_CHECK(librustzcash_sapling_ka_derivepublic(pk_1.d.begin(), test_esk.begin(), test_epk.begin()));
     196           2 :         BOOST_CHECK(test_epk == epk_1);
     197             :     }
     198           1 :     auto cv_1 = random_uint256();
     199           1 :     auto cm_1 = random_uint256();
     200           1 :     auto out_ciphertext_1 = enc.encrypt_to_ourselves(
     201             :             sk.ovk,
     202             :             cv_1,
     203             :             cm_1,
     204             :             small_message
     205           1 :     );
     206             : 
     207             :     // Encrypt to pk_2
     208           2 :     enc = *libzcash::SaplingNoteEncryption::FromDiversifier(pk_2.d);
     209           1 :     auto ciphertext_2 = *enc.encrypt_to_recipient(
     210             :             pk_2.pk_d,
     211             :             message
     212             :     );
     213           1 :     auto epk_2 = enc.get_epk();
     214             : 
     215           1 :     auto cv_2 = random_uint256();
     216           1 :     auto cm_2 = random_uint256();
     217           1 :     auto out_ciphertext_2 = enc.encrypt_to_ourselves(
     218             :             sk.ovk,
     219             :             cv_2,
     220             :             cm_2,
     221             :             small_message
     222           1 :     );
     223             : 
     224             :     // Test nonce-reuse resistance of API
     225           1 :     {
     226           2 :         auto tmp_enc = *libzcash::SaplingNoteEncryption::FromDiversifier(pk_1.d);
     227             : 
     228           1 :         tmp_enc.encrypt_to_recipient(
     229             :                 pk_1.pk_d,
     230             :                 message
     231             :                 );
     232             : 
     233           2 :         BOOST_CHECK_THROW(tmp_enc.encrypt_to_recipient(
     234             :                 pk_1.pk_d,
     235             :                 message
     236             :                 ), std::logic_error);
     237             : 
     238           2 :         tmp_enc.encrypt_to_ourselves(
     239             :                 sk.ovk,
     240             :                 cv_2,
     241             :                 cm_2,
     242             :                 small_message
     243           1 :                 );
     244             : 
     245           2 :         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           1 :     auto plaintext_1 = *AttemptSaplingEncDecryption(
     255             :             ciphertext_1,
     256             :             ivk,
     257             :             epk_1
     258           1 :     );
     259           2 :     BOOST_CHECK(message == plaintext_1);
     260             : 
     261           1 :     auto small_plaintext_1 = *libzcash::AttemptSaplingOutDecryption(
     262             :             out_ciphertext_1,
     263             :             sk.ovk,
     264             :             cv_1,
     265             :             cm_1,
     266             :             epk_1
     267           1 :     );
     268           2 :     BOOST_CHECK(small_message == small_plaintext_1);
     269             : 
     270           1 :     auto plaintext_2 = *AttemptSaplingEncDecryption(
     271             :             ciphertext_2,
     272             :             ivk,
     273             :             epk_2
     274           1 :     );
     275           2 :     BOOST_CHECK(message == plaintext_2);
     276             : 
     277           1 :     auto small_plaintext_2 = *libzcash::AttemptSaplingOutDecryption(
     278             :             out_ciphertext_2,
     279             :             sk.ovk,
     280             :             cv_2,
     281             :             cm_2,
     282             :             epk_2
     283           1 :     );
     284           2 :     BOOST_CHECK(small_message == small_plaintext_2);
     285             : 
     286             :     // Try to decrypt out ciphertext with wrong key material
     287           2 :     BOOST_CHECK(!libzcash::AttemptSaplingOutDecryption(
     288             :             out_ciphertext_1,
     289             :             random_uint256(),
     290             :             cv_1,
     291             :             cm_1,
     292             :             epk_1
     293             :     ));
     294           2 :     BOOST_CHECK(!libzcash::AttemptSaplingOutDecryption(
     295             :             out_ciphertext_1,
     296             :             sk.ovk,
     297             :             random_uint256(),
     298             :             cm_1,
     299             :             epk_1
     300             :     ));
     301           2 :     BOOST_CHECK(!libzcash::AttemptSaplingOutDecryption(
     302             :             out_ciphertext_1,
     303             :             sk.ovk,
     304             :             cv_1,
     305             :             random_uint256(),
     306             :             epk_1
     307             :     ));
     308           2 :     BOOST_CHECK(!libzcash::AttemptSaplingOutDecryption(
     309             :             out_ciphertext_1,
     310             :             sk.ovk,
     311             :             cv_1,
     312             :             cm_1,
     313             :             random_uint256()
     314             :     ));
     315             : 
     316             :     // Try to decrypt with wrong ephemeral key
     317           2 :     BOOST_CHECK(!AttemptSaplingEncDecryption(
     318             :             ciphertext_1,
     319             :             ivk,
     320             :             epk_2
     321             :     ));
     322           2 :     BOOST_CHECK(!AttemptSaplingEncDecryption(
     323             :             ciphertext_2,
     324             :             ivk,
     325             :             epk_1
     326             :     ));
     327             : 
     328             :     // Try to decrypt with wrong ivk
     329           3 :     BOOST_CHECK(!libzcash::AttemptSaplingEncDecryption(
     330             :             ciphertext_1,
     331             :             uint256(),
     332             :             epk_1
     333             :     ));
     334           3 :     BOOST_CHECK(!libzcash::AttemptSaplingEncDecryption(
     335             :             ciphertext_2,
     336             :             uint256(),
     337             :             epk_2
     338             :     ));
     339           1 : }
     340             : 
     341             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14