LCOV - code coverage report
Current view: top level - src/sapling - note.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 90 99 90.9 %
Date: 2026-08-09 10:51:41 Functions: 10 10 100.0 %

          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             : }

Generated by: LCOV version 1.14