LCOV - code coverage report
Current view: top level - src/sapling - key_io_sapling.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 83 87 95.4 %
Date: 2025-02-23 09:33:43 Functions: 11 11 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2016-2018 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 "sapling/key_io_sapling.h"
       7             : 
       8             : #include "utilstrencodings.h"
       9             : #include "bech32.h"
      10             : #include "script/script.h"
      11             : #include "streams.h"
      12             : 
      13             : #include <boost/variant/apply_visitor.hpp>
      14             : #include <boost/variant/static_visitor.hpp>
      15             : 
      16             : #include <assert.h>
      17             : #include <string.h>
      18             : #include <algorithm>
      19             : 
      20             : class PaymentAddressEncoder : public boost::static_visitor<std::string>
      21             : {
      22             : private:
      23             :     const CChainParams& m_params;
      24             : 
      25             : public:
      26       10211 :     explicit PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
      27             : 
      28       10211 :     std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const
      29             :     {
      30       10211 :         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
      31       10211 :         ss << zaddr;
      32             :         // ConvertBits requires unsigned char, but CDataStream uses char
      33       20422 :         std::vector<unsigned char> seraddr(ss.begin(), ss.end());
      34       20422 :         std::vector<unsigned char> data;
      35             :         // See calculation comment below
      36       10211 :         data.reserve((seraddr.size() * 8 + 4) / 5);
      37      714770 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
      38       20422 :         return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data);
      39             :     }
      40             : 
      41           0 :     std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
      42             : };
      43             : 
      44             : class ViewingKeyEncoder : public boost::static_visitor<std::string>
      45             : {
      46             : private:
      47             :     const CChainParams& m_params;
      48             : 
      49             : public:
      50        1003 :     explicit ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
      51             : 
      52        1003 :     std::string operator()(const libzcash::SaplingExtendedFullViewingKey& extfvk) const
      53             :     {
      54        1003 :         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
      55        1003 :         ss << extfvk;
      56             :         // ConvertBits requires unsigned char, but CDataStream uses char
      57        2006 :         std::vector<unsigned char> serkey(ss.begin(), ss.end());
      58        2006 :         std::vector<unsigned char> data;
      59             :         // See calculation comment below
      60        1003 :         data.reserve((serkey.size() * 8 + 4) / 5);
      61      272816 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
      62        1003 :         std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK), data);
      63        1003 :         memory_cleanse(serkey.data(), serkey.size());
      64        1003 :         memory_cleanse(data.data(), data.size());
      65        2006 :         return ret;
      66             :     }
      67             : 
      68           0 :     std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
      69             : };
      70             : 
      71             : class SpendingKeyEncoder : public boost::static_visitor<std::string>
      72             : {
      73             : private:
      74             :     const CChainParams& m_params;
      75             : 
      76             : public:
      77        4005 :     explicit SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
      78             : 
      79        4005 :     std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const
      80             :     {
      81        4005 :         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
      82        4005 :         ss << zkey;
      83             :         // ConvertBits requires unsigned char, but CDataStream uses char
      84        8010 :         std::vector<unsigned char> serkey(ss.begin(), ss.end());
      85        8010 :         std::vector<unsigned char> data;
      86             :         // See calculation comment below
      87        4005 :         data.reserve((serkey.size() * 8 + 4) / 5);
      88     1089358 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
      89        4005 :         std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data);
      90        4005 :         memory_cleanse(serkey.data(), serkey.size());
      91        4005 :         memory_cleanse(data.data(), data.size());
      92        8010 :         return ret;
      93             :     }
      94             : 
      95           0 :     std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
      96             : };
      97             : 
      98             : namespace KeyIO {
      99             : 
     100             :     // Sizes of SaplingPaymentAddress, SaplingExtendedFullViewingKey, and
     101             :     // SaplingExtendedSpendingKey after ConvertBits<8, 5, true>(). The calculations
     102             :     // below take the regular serialized size in bytes, convert to bits, and then
     103             :     // perform ceiling division to get the number of 5-bit clusters.
     104             :     const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5;
     105             :     const size_t ConvertedSaplingExtendedFullViewingKeySize = (ZIP32_XFVK_SIZE * 8 + 4) / 5;
     106             :     const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5;
     107             : 
     108       10211 :     std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
     109             :     {
     110       10211 :         return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
     111             :     }
     112             : 
     113        4392 :     libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
     114             :     {
     115        8784 :         std::vector<unsigned char> data;
     116        8784 :         auto bech = bech32::Decode(str);
     117        4392 :         if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
     118        4380 :             bech.second.size() == ConvertedSaplingPaymentAddressSize) {
     119             :             // Bech32 decoding
     120        4380 :             data.reserve((bech.second.size() * 5) / 8);
     121      192720 :             if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
     122        8760 :                 CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
     123        4380 :                 libzcash::SaplingPaymentAddress ret;
     124        4380 :                 ss >> ret;
     125        4380 :                 return ret;
     126             :             }
     127             :         }
     128          12 :         return libzcash::InvalidEncoding();
     129             :     }
     130             : 
     131         216 :     Optional<libzcash::SaplingPaymentAddress> DecodeSaplingPaymentAddress(const std::string& strAddress)
     132             :     {
     133         216 :         libzcash::PaymentAddress addr = KeyIO::DecodePaymentAddress(strAddress);
     134         216 :         const auto dest = boost::get<libzcash::SaplingPaymentAddress>(&addr);
     135         424 :         return (dest) ? Optional<libzcash::SaplingPaymentAddress>(*dest) : nullopt;
     136             :     }
     137             : 
     138           4 :     bool IsValidPaymentAddressString(const std::string& str) {
     139           4 :         return IsValidPaymentAddress(DecodePaymentAddress(str));
     140             :     }
     141             : 
     142        1003 :     std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
     143             :     {
     144        1003 :         return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
     145             :     }
     146             : 
     147        1003 :     libzcash::ViewingKey DecodeViewingKey(const std::string& str)
     148             :     {
     149        2006 :         auto bech = bech32::Decode(str);
     150        1003 :         if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK) &&
     151        1003 :             bech.second.size() == ConvertedSaplingExtendedFullViewingKeySize) {
     152        1003 :             std::vector<unsigned char> data;
     153             :             // Bech32 decoding
     154        1003 :             data.reserve((bech.second.size() * 5) / 8);
     155      170510 :             if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
     156        2006 :                 CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
     157        1003 :                 libzcash::SaplingExtendedFullViewingKey ret;
     158        1003 :                 ss >> ret;
     159        1003 :                 memory_cleanse(data.data(), data.size());
     160        1003 :                 return ret;
     161             :             }
     162             :         }
     163           0 :         return libzcash::InvalidEncoding();
     164             :     }
     165             : 
     166        4005 :     std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
     167             :     {
     168        4005 :         return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
     169             :     }
     170             : 
     171        3940 :     libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
     172             :     {
     173        7880 :         std::vector<unsigned char> data;
     174        7880 :         auto bech = bech32::Decode(str);
     175        3940 :         if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
     176        3007 :             bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
     177             :             // Bech32 decoding
     178        3007 :             data.reserve((bech.second.size() * 5) / 8);
     179      511190 :             if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
     180        6014 :                 CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
     181        3007 :                 libzcash::SaplingExtendedSpendingKey ret;
     182        3007 :                 ss >> ret;
     183        3007 :                 memory_cleanse(data.data(), data.size());
     184        3007 :                 return ret;
     185             :             }
     186             :         }
     187         933 :         memory_cleanse(data.data(), data.size());
     188         933 :         return libzcash::InvalidEncoding();
     189             :     }
     190             : 
     191             : } // KeyIO namespace

Generated by: LCOV version 1.14