diff --git a/src/base58.cpp b/src/base58.cpp index 9649a681..efce9186 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -347,3 +347,37 @@ libzcash::PaymentAddress CZCPaymentAddress::Get() const return ret; } +const size_t serializedSpendingKeySize = 32; + +bool CZCSpendingKey::Set(const libzcash::SpendingKey& addr) +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << addr; + std::vector addrSerialized(ss.begin(), ss.end()); + assert(addrSerialized.size() == serializedSpendingKeySize); + SetData(Params().Base58Prefix(CChainParams::ZCSPENDING_KEY), &addrSerialized[0], serializedSpendingKeySize); + return true; +} + +libzcash::SpendingKey CZCSpendingKey::Get() const +{ + if (vchData.size() != serializedSpendingKeySize) { + throw std::runtime_error( + "spending key is invalid" + ); + } + + if (vchVersion != Params().Base58Prefix(CChainParams::ZCSPENDING_KEY)) { + throw std::runtime_error( + "spending key is for wrong network type" + ); + } + + std::vector serialized(vchData.begin(), vchData.end()); + + CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); + libzcash::SpendingKey ret; + ss >> ret; + return ret; +} + diff --git a/src/base58.h b/src/base58.h index 27f564cc..8a442b1b 100644 --- a/src/base58.h +++ b/src/base58.h @@ -107,6 +107,17 @@ public: libzcash::PaymentAddress Get() const; }; +class CZCSpendingKey : public CBase58Data { +public: + bool Set(const libzcash::SpendingKey& addr); + CZCSpendingKey() {} + + CZCSpendingKey(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } + CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); } + + libzcash::SpendingKey Get() const; +}; + /** base58-encoded Bitcoin addresses. * Public-key-hash-addresses have version 0 (or 111 testnet). * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c73c68ce..8246a566 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -107,6 +107,7 @@ public: base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); // guarantees the first two characters, when base58 encoded, are "zc" base58Prefixes[ZCPAYMENT_ADDRRESS] = {22,154}; + base58Prefixes[ZCSPENDING_KEY] = {22,180}; vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); @@ -185,6 +186,7 @@ public: base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container >(); base58Prefixes[ZCPAYMENT_ADDRRESS] = {22,155}; + base58Prefixes[ZCSPENDING_KEY] = {22,181}; vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); diff --git a/src/chainparams.h b/src/chainparams.h index 86d2dfb9..de89fa0e 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -43,6 +43,7 @@ public: EXT_SECRET_KEY, ZCPAYMENT_ADDRRESS, + ZCSPENDING_KEY, MAX_BASE58_TYPES }; diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index d6f97696..f15226ea 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -195,19 +195,28 @@ BOOST_AUTO_TEST_CASE(zc_address_test) { for (size_t i = 0; i < 1000; i++) { auto sk = SpendingKey::random(); - auto addr = sk.address(); + { + CZCSpendingKey spendingkey(sk); + string sk_string = spendingkey.ToString(); + CZCSpendingKey spendingkey2(sk_string); + SpendingKey sk2 = spendingkey2.Get(); + BOOST_CHECK(sk.inner() == sk2.inner()); + } + { + auto addr = sk.address(); - CZCPaymentAddress paymentaddr(addr); - string addr_string = paymentaddr.ToString(); + CZCPaymentAddress paymentaddr(addr); + string addr_string = paymentaddr.ToString(); - BOOST_CHECK(addr_string[0] == 'z'); - BOOST_CHECK(addr_string[1] == 'c'); + BOOST_CHECK(addr_string[0] == 'z'); + BOOST_CHECK(addr_string[1] == 'c'); - CZCPaymentAddress paymentaddr2(addr_string); + CZCPaymentAddress paymentaddr2(addr_string); - PaymentAddress addr2 = paymentaddr2.Get(); - BOOST_CHECK(addr.a_pk == addr2.a_pk); - BOOST_CHECK(addr.pk_enc == addr2.pk_enc); + PaymentAddress addr2 = paymentaddr2.Get(); + BOOST_CHECK(addr.a_pk == addr2.a_pk); + BOOST_CHECK(addr.pk_enc == addr2.pk_enc); + } } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a2027aec..ae3354c2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2459,18 +2459,8 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp) LOCK(cs_main); - SpendingKey k; - - { - CDataStream ssData(ParseHexV(params[0], "zcsecretkey"), SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> k; - } catch(const std::exception &) { - throw runtime_error( - "zcsecretkey could not be decoded" - ); - } - } + CZCSpendingKey spendingkey(params[0].get_str()); + SpendingKey k = spendingkey.Get(); uint256 epk; unsigned char nonce; @@ -2581,18 +2571,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp) BOOST_FOREACH(const Pair& s, inputs) { - SpendingKey k; - - { - CDataStream ssData(ParseHexV(s.value_, "zcsecretkey"), SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> k; - } catch(const std::exception &) { - throw runtime_error( - "zcsecretkey could not be decoded" - ); - } - } + CZCSpendingKey spendingkey(s.value_.get_str()); + SpendingKey k = spendingkey.Get(); keys.push_back(k); @@ -2748,19 +2728,17 @@ Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp) auto addr = k.address(); auto viewing_key = k.viewing_key(); - CDataStream priv(SER_NETWORK, PROTOCOL_VERSION); CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION); - priv << k; viewing << viewing_key; CZCPaymentAddress pubaddr(addr); - std::string priv_hex = HexStr(priv.begin(), priv.end()); + CZCSpendingKey spendingkey(k); std::string viewing_hex = HexStr(viewing.begin(), viewing.end()); Object result; result.push_back(Pair("zcaddress", pubaddr.ToString())); - result.push_back(Pair("zcsecretkey", priv_hex)); + result.push_back(Pair("zcsecretkey", spendingkey.ToString())); result.push_back(Pair("zcviewingkey", viewing_hex)); return result; }