]> Git Repo - VerusCoin.git/commitdiff
Implement encoding and decoding of Sapling keys and addresses
authorJack Grigg <[email protected]>
Thu, 7 Jun 2018 04:40:59 +0000 (16:40 +1200)
committerJack Grigg <[email protected]>
Thu, 7 Jun 2018 05:28:50 +0000 (17:28 +1200)
src/key_io.cpp
src/test/key_tests.cpp
src/zcash/Address.hpp

index a7f614f2543c5520d8e348ea24198b708b0a9c0d..c73a3703f3c21eb509aa7308cb0779dced870897 100644 (file)
@@ -85,6 +85,18 @@ public:
         return EncodeBase58Check(data);
     }
 
+    std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const
+    {
+        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+        ss << zaddr;
+        // ConvertBits requires unsigned char, but CDataStream uses char
+        std::vector<unsigned char> seraddr(ss.begin(), ss.end());
+        std::vector<unsigned char> data;
+        data.reserve((seraddr.size() * 8 + 4) / 5);
+        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
+        return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data);
+    }
+
     std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
 };
 
@@ -129,8 +141,26 @@ public:
         return ret;
     }
 
+    std::string operator()(const libzcash::SaplingSpendingKey& zkey) const
+    {
+        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+        ss << zkey;
+        // ConvertBits requires unsigned char, but CDataStream uses char
+        std::vector<unsigned char> serkey(ss.begin(), ss.end());
+        std::vector<unsigned char> data;
+        data.reserve((serkey.size() * 8 + 4) / 5);
+        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
+        std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_SPENDING_KEY), data);
+        memory_cleanse(serkey.data(), serkey.size());
+        memory_cleanse(data.data(), data.size());
+        return ret;
+    }
+
     std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
 };
+
+const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5;
+const size_t ConvertedSaplingSpendingKeySize = (32 * 8 + 4) / 5;
 } // namespace
 
 CKey DecodeSecret(const std::string& str)
@@ -248,6 +278,19 @@ libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
             return ret;
         }
     }
+    data.clear();
+    auto bech = bech32::Decode(str);
+    if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
+        bech.second.size() == ConvertedSaplingPaymentAddressSize) {
+        // Bech32 decoding
+        data.reserve((bech.second.size() * 5) / 8);
+        if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
+            CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
+            libzcash::SaplingPaymentAddress ret;
+            ss >> ret;
+            return ret;
+        }
+    }
     return libzcash::InvalidEncoding();
 }
 
@@ -301,6 +344,20 @@ libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
             return ret;
         }
     }
+    data.clear();
+    auto bech = bech32::Decode(str);
+    if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_SPENDING_KEY) &&
+        bech.second.size() == ConvertedSaplingSpendingKeySize) {
+        // Bech32 decoding
+        data.reserve((bech.second.size() * 5) / 8);
+        if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
+            CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
+            libzcash::SaplingSpendingKey ret;
+            ss >> ret;
+            memory_cleanse(data.data(), data.size());
+            return ret;
+        }
+    }
     memory_cleanse(data.data(), data.size());
     return libzcash::InvalidEncoding();
 }
index 9c7385419f2d2478e3f416616a6813e80219161d..25c30c22345eb7b977a9c8b39ba9e3d77d7dead0 100644 (file)
@@ -220,4 +220,35 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
     }
 }
 
+BOOST_AUTO_TEST_CASE(zs_address_test)
+{
+    for (size_t i = 0; i < 1000; i++) {
+        auto sk = SaplingSpendingKey::random();
+        {
+            std::string sk_string = EncodeSpendingKey(sk);
+            BOOST_CHECK(sk_string.compare(0, 24, "secret-spending-key-main") == 0);
+
+            auto spendingkey2 = DecodeSpendingKey(sk_string);
+            BOOST_CHECK(IsValidSpendingKey(spendingkey2));
+
+            BOOST_ASSERT(boost::get<SaplingSpendingKey>(&spendingkey2) != nullptr);
+            auto sk2 = boost::get<SaplingSpendingKey>(spendingkey2);
+            BOOST_CHECK(sk == sk2);
+        }
+        {
+            auto addr = sk.default_address();
+
+            std::string addr_string = EncodePaymentAddress(*addr);
+            BOOST_CHECK(addr_string.compare(0, 2, "zs") == 0);
+
+            auto paymentaddr2 = DecodePaymentAddress(addr_string);
+            BOOST_CHECK(IsValidPaymentAddress(paymentaddr2));
+
+            BOOST_ASSERT(boost::get<SaplingPaymentAddress>(&paymentaddr2) != nullptr);
+            auto addr2 = boost::get<SaplingPaymentAddress>(paymentaddr2);
+            BOOST_CHECK(addr == addr2);
+        }
+    }
+}
+
 BOOST_AUTO_TEST_SUITE_END()
index 6b8c310f4099bd763c160f447620d8108fc6beb2..614defdde3f8fcd813b4df0ae6f652dafbb85eb5 100644 (file)
@@ -95,10 +95,6 @@ public:
     SproutPaymentAddress address() const;
 };
 
-typedef boost::variant<InvalidEncoding, SproutPaymentAddress> PaymentAddress;
-typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
-typedef boost::variant<InvalidEncoding, SproutSpendingKey> SpendingKey;
-
 //! Sapling functions. 
 class SaplingPaymentAddress {
 public:
@@ -209,6 +205,10 @@ public:
     boost::optional<SaplingPaymentAddress> default_address() const;
 };
 
+typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
+typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
+typedef boost::variant<InvalidEncoding, SproutSpendingKey, SaplingSpendingKey> SpendingKey;
+
 }
 
 /** Check whether a PaymentAddress is not an InvalidEncoding. */
This page took 0.039172 seconds and 4 git commands to generate.