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 {}; }
};
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)
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();
}
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();
}
}
}
+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()
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:
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. */