From 9e8e121c9f115b9b772f54a17e11cd0eec6ea4b5 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 13 Jun 2018 15:17:53 -0600 Subject: [PATCH 1/6] Update librustzcash --- depends/packages/librustzcash.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index 11ee085f441..3a338cc21d6 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -3,8 +3,8 @@ $(package)_version=0.1 $(package)_download_path=https://github.com/zcash/$(package)/archive/ $(package)_file_name=$(package)-$($(package)_git_commit).tar.gz $(package)_download_file=$($(package)_git_commit).tar.gz -$(package)_sha256_hash=5231145ea6abf61092c21b6770baf3af65994f83dff96b10118ba5dd53451f26 -$(package)_git_commit=0af1ce8bf121e1ad367db907c39d214581e270a6 +$(package)_sha256_hash=5a50aae38a9ef4823cd319278ad95706a129cc091e1cca9342802f1ff75aba15 +$(package)_git_commit=93e26d1d8716ac88f8bb372d442315edcd2deabd $(package)_dependencies=rust $(rust_crates) $(package)_patches=cargo.config From 9e1c2c4049b84deb6ec0eff1e7a0e505f542848f Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 14 Jun 2018 11:58:45 -0600 Subject: [PATCH 2/6] Implementation of Sapling in-band secret distribution. --- src/gtest/test_noteencryption.cpp | 149 +++++++++++++++++++++++ src/zcash/Address.hpp | 3 +- src/zcash/NoteEncryption.cpp | 190 ++++++++++++++++++++++++++++++ src/zcash/NoteEncryption.hpp | 60 +++++++++- src/zcash/Zcash.h | 11 ++ 5 files changed, 411 insertions(+), 2 deletions(-) diff --git a/src/gtest/test_noteencryption.cpp b/src/gtest/test_noteencryption.cpp index 75483217935..6c22daeeb8f 100644 --- a/src/gtest/test_noteencryption.cpp +++ b/src/gtest/test_noteencryption.cpp @@ -6,6 +6,7 @@ #include "zcash/NoteEncryption.hpp" #include "zcash/prf.h" +#include "zcash/Address.hpp" #include "crypto/sha256.h" class TestNoteDecryption : public ZCNoteDecryption { @@ -17,6 +18,154 @@ class TestNoteDecryption : public ZCNoteDecryption { } }; +TEST(noteencryption, sapling_api) +{ + using namespace libzcash; + + // Create recipient addresses + auto sk = SaplingSpendingKey(uint256()).expanded_spending_key(); + auto vk = sk.full_viewing_key(); + auto ivk = vk.in_viewing_key(); + SaplingPaymentAddress pk_1 = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + SaplingPaymentAddress pk_2 = *ivk.address({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + + // Blob of stuff we're encrypting + std::array message; + for (size_t i = 0; i < ZC_SAPLING_ENCPLAINTEXT_SIZE; i++) { + // Fill the message with dummy data + message[i] = (unsigned char) i; + } + + std::array small_message; + for (size_t i = 0; i < ZC_SAPLING_OUTPLAINTEXT_SIZE; i++) { + // Fill the message with dummy data + small_message[i] = (unsigned char) i; + } + + // Invalid diversifier + ASSERT_FALSE(SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); + + // Encrypt to pk_1 + auto enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d); + auto ciphertext_1 = *enc.encrypt_to_recipient( + pk_1.pk_d, + message + ); + auto epk_1 = enc.get_epk(); + auto cv_1 = random_uint256(); + auto cm_1 = random_uint256(); + auto out_ciphertext_1 = enc.encrypt_to_ourselves( + sk.ovk, + cv_1, + cm_1, + small_message + ); + + // Encrypt to pk_2 + enc = *SaplingNoteEncryption::FromDiversifier(pk_2.d); + auto ciphertext_2 = *enc.encrypt_to_recipient( + pk_2.pk_d, + message + ); + auto epk_2 = enc.get_epk(); + + auto cv_2 = random_uint256(); + auto cm_2 = random_uint256(); + auto out_ciphertext_2 = enc.encrypt_to_ourselves( + sk.ovk, + cv_2, + cm_2, + small_message + ); + + // Try to decrypt + auto plaintext_1 = *AttemptSaplingEncDecryption( + ciphertext_1, + ivk, + epk_1 + ); + ASSERT_TRUE(message == plaintext_1); + + auto small_plaintext_1 = *AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + cv_1, + cm_1, + epk_1 + ); + ASSERT_TRUE(small_message == small_plaintext_1); + + auto plaintext_2 = *AttemptSaplingEncDecryption( + ciphertext_2, + ivk, + epk_2 + ); + ASSERT_TRUE(message == plaintext_2); + + auto small_plaintext_2 = *AttemptSaplingOutDecryption( + out_ciphertext_2, + sk.ovk, + cv_2, + cm_2, + epk_2 + ); + ASSERT_TRUE(small_message == small_plaintext_2); + + // Try to decrypt out ciphertext with wrong key material + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + random_uint256(), + cv_1, + cm_1, + epk_1 + )); + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + random_uint256(), + cm_1, + epk_1 + )); + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + cv_1, + random_uint256(), + epk_1 + )); + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + cv_1, + cm_1, + random_uint256() + )); + + // Try to decrypt with wrong ephemeral key + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_1, + ivk, + epk_2 + )); + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_2, + ivk, + epk_1 + )); + + // Try to decrypt with wrong ivk + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_1, + uint256(), + epk_1 + )); + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_2, + uint256(), + epk_2 + )); +} + TEST(noteencryption, api) { uint256 sk_enc = ZCNoteEncryption::generate_privkey(uint252(uint256S("21035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a07"))); diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index 6b8c310f409..b19a0b8993f 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -4,6 +4,7 @@ #include "uint256.h" #include "uint252.h" #include "serialize.h" +#include "Zcash.h" #include @@ -18,7 +19,7 @@ const size_t SerializedPaymentAddressSize = 64; const size_t SerializedViewingKeySize = 64; const size_t SerializedSpendingKeySize = 32; -typedef std::array diversifier_t; +typedef std::array diversifier_t; class SproutPaymentAddress { public: diff --git a/src/zcash/NoteEncryption.cpp b/src/zcash/NoteEncryption.cpp index 9ae0ba5c342..27e8b0b88f9 100644 --- a/src/zcash/NoteEncryption.cpp +++ b/src/zcash/NoteEncryption.cpp @@ -3,6 +3,7 @@ #include "sodium.h" #include #include "prf.h" +#include "librustzcash.h" #define NOTEENCRYPTION_CIPHER_KEYSIZE 32 @@ -13,6 +14,58 @@ void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES]) key[31] |= 64; } +void PRF_ock( + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], + const uint256 &ovk, + const uint256 &cv, + const uint256 &cm, + const uint256 &epk +) +{ + unsigned char block[128] = {}; + memcpy(block+0, ovk.begin(), 32); + memcpy(block+32, cv.begin(), 32); + memcpy(block+64, cm.begin(), 32); + memcpy(block+96, epk.begin(), 32); + + unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; + memcpy(personalization, "Zcash_Derive_ock", 16); + + if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE, + block, 128, + NULL, 0, // No key. + NULL, // No salt. + personalization + ) != 0) + { + throw std::logic_error("hash function failure"); + } +} + +void KDF_Sapling( + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], + const uint256 &dhsecret, + const uint256 &epk +) +{ + unsigned char block[64] = {}; + memcpy(block+0, dhsecret.begin(), 32); + memcpy(block+32, epk.begin(), 32); + + unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; + memcpy(personalization, "Zcash_SaplingKDF", 16); + + if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE, + block, 64, + NULL, 0, // No key. + NULL, // No salt. + personalization + ) != 0) + { + throw std::logic_error("hash function failure"); + } +} + void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], const uint256 &dhsecret, const uint256 &epk, @@ -48,6 +101,143 @@ void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], namespace libzcash { +boost::optional SaplingNoteEncryption::FromDiversifier(diversifier_t d) { + uint256 epk; + uint256 esk; + + // Pick random esk + librustzcash_sapling_generate_r(esk.begin()); + + // Compute epk given the diversifier + if (!librustzcash_sapling_ka_derivepublic(d.begin(), esk.begin(), epk.begin())) { + return boost::none; + } + + return SaplingNoteEncryption(epk, esk); +} + +boost::optional SaplingNoteEncryption::encrypt_to_recipient( + const uint256 &pk_d, + const SaplingEncPlaintext &message +) +{ + uint256 dhsecret; + + if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) { + return boost::none; + } + + // Construct the symmetric key + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; + KDF_Sapling(K, dhsecret, epk); + + // The nonce is zero because we never reuse keys + unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {}; + + SaplingEncCiphertext ciphertext; + + crypto_aead_chacha20poly1305_ietf_encrypt( + ciphertext.begin(), NULL, + message.begin(), ZC_SAPLING_ENCPLAINTEXT_SIZE, + NULL, 0, // no "additional data" + NULL, cipher_nonce, K + ); + + return ciphertext; +} + +boost::optional AttemptSaplingEncDecryption( + const SaplingEncCiphertext &ciphertext, + const uint256 &ivk, + const uint256 &epk +) +{ + uint256 dhsecret; + + if (!librustzcash_sapling_ka_agree(epk.begin(), ivk.begin(), dhsecret.begin())) { + return boost::none; + } + + // Construct the symmetric key + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; + KDF_Sapling(K, dhsecret, epk); + + // The nonce is zero because we never reuse keys + unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {}; + + SaplingEncPlaintext plaintext; + + if (crypto_aead_chacha20poly1305_ietf_decrypt( + plaintext.begin(), NULL, + NULL, + ciphertext.begin(), ZC_SAPLING_ENCCIPHERTEXT_SIZE, + NULL, + 0, + cipher_nonce, K) != 0) + { + return boost::none; + } + + return plaintext; +} + +SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves( + const uint256 &ovk, + const uint256 &cv, + const uint256 &cm, + const SaplingOutPlaintext &message +) +{ + // Construct the symmetric key + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; + PRF_ock(K, ovk, cv, cm, epk); + + // The nonce is zero because we never reuse keys + unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {}; + + SaplingOutCiphertext ciphertext; + + crypto_aead_chacha20poly1305_ietf_encrypt( + ciphertext.begin(), NULL, + message.begin(), ZC_SAPLING_OUTPLAINTEXT_SIZE, + NULL, 0, // no "additional data" + NULL, cipher_nonce, K + ); + + return ciphertext; +} + +boost::optional AttemptSaplingOutDecryption( + const SaplingOutCiphertext &ciphertext, + const uint256 &ovk, + const uint256 &cv, + const uint256 &cm, + const uint256 &epk +) +{ + // Construct the symmetric key + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; + PRF_ock(K, ovk, cv, cm, epk); + + // The nonce is zero because we never reuse keys + unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {}; + + SaplingOutPlaintext plaintext; + + if (crypto_aead_chacha20poly1305_ietf_decrypt( + plaintext.begin(), NULL, + NULL, + ciphertext.begin(), ZC_SAPLING_OUTCIPHERTEXT_SIZE, + NULL, + 0, + cipher_nonce, K) != 0) + { + return boost::none; + } + + return plaintext; +} + template NoteEncryption::NoteEncryption(uint256 hSig) : nonce(0), hSig(hSig) { // All of this code assumes crypto_scalarmult_BYTES is 32 diff --git a/src/zcash/NoteEncryption.hpp b/src/zcash/NoteEncryption.hpp index 86de8f44b1e..47fc93f7e05 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -10,12 +10,70 @@ See the Zcash protocol specification for more information. #include "uint252.h" #include "zcash/Zcash.h" +#include "zcash/Address.hpp" #include namespace libzcash { -#define NOTEENCRYPTION_AUTH_BYTES 16 +// Ciphertext for the recipient to decrypt +typedef std::array SaplingEncCiphertext; +typedef std::array SaplingEncPlaintext; + +// Ciphertext for outgoing viewing key to decrypt +typedef std::array SaplingOutCiphertext; +typedef std::array SaplingOutPlaintext; + +class SaplingNoteEncryption { +protected: + // Ephemeral public key + uint256 epk; + + // Ephemeral secret key + uint256 esk; + + SaplingNoteEncryption(uint256 epk, uint256 esk) : epk(epk), esk(esk) { + + } + +public: + + static boost::optional FromDiversifier(diversifier_t d); + + boost::optional encrypt_to_recipient( + const uint256 &pk_d, + const SaplingEncPlaintext &message + ); + + SaplingOutCiphertext encrypt_to_ourselves( + const uint256 &ovk, + const uint256 &cv, + const uint256 &cm, + const SaplingOutPlaintext &message + ); + + uint256 get_epk() const { + return epk; + } +}; + +// Attempts to decrypt a Sapling note. This will not check that the contents +// of the ciphertext are correct. +boost::optional AttemptSaplingEncDecryption( + const SaplingEncCiphertext &ciphertext, + const uint256 &ivk, + const uint256 &epk +); + +// Attempts to decrypt a Sapling note. This will not check that the contents +// of the ciphertext are correct. +boost::optional AttemptSaplingOutDecryption( + const SaplingOutCiphertext &ciphertext, + const uint256 &ovk, + const uint256 &cv, + const uint256 &cm, + const uint256 &epk +); template class NoteEncryption { diff --git a/src/zcash/Zcash.h b/src/zcash/Zcash.h index bb805eef5ef..84dfe9525fb 100644 --- a/src/zcash/Zcash.h +++ b/src/zcash/Zcash.h @@ -8,12 +8,23 @@ #define SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH 32 +#define NOTEENCRYPTION_AUTH_BYTES 16 + #define ZC_NOTEPLAINTEXT_LEADING 1 #define ZC_V_SIZE 8 #define ZC_RHO_SIZE 32 #define ZC_R_SIZE 32 #define ZC_MEMO_SIZE 512 +#define ZC_DIVERSIFIER_SIZE 11 +#define ZC_JUBJUB_POINT_SIZE 32 +#define ZC_JUBJUB_SCALAR_SIZE 32 #define ZC_NOTEPLAINTEXT_SIZE (ZC_NOTEPLAINTEXT_LEADING + ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE) +#define ZC_SAPLING_ENCPLAINTEXT_SIZE (ZC_NOTEPLAINTEXT_LEADING + ZC_DIVERSIFIER_SIZE + ZC_V_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE) +#define ZC_SAPLING_OUTPLAINTEXT_SIZE (ZC_JUBJUB_POINT_SIZE + ZC_JUBJUB_SCALAR_SIZE) + +#define ZC_SAPLING_ENCCIPHERTEXT_SIZE (ZC_SAPLING_ENCPLAINTEXT_SIZE + NOTEENCRYPTION_AUTH_BYTES) +#define ZC_SAPLING_OUTCIPHERTEXT_SIZE (ZC_SAPLING_OUTPLAINTEXT_SIZE + NOTEENCRYPTION_AUTH_BYTES) + #endif // ZC_ZCASH_H_ From 90073aeca590f6b1a9b5b807d5998b9ea4567d05 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 14 Jun 2018 12:08:37 -0600 Subject: [PATCH 3/6] Swap types in OutputDescription to use new NoteEncryption interfaces. --- src/primitives/transaction.h | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 715c8672f75..4295dea9fe4 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -84,33 +84,17 @@ class SpendDescription } }; -static constexpr size_t SAPLING_ENC_CIPHERTEXT_SIZE = ( - 1 + // leading byte - 11 + // d - 8 + // value - 32 + // rcm - ZC_MEMO_SIZE + // memo - NOTEENCRYPTION_AUTH_BYTES); - -static constexpr size_t SAPLING_OUT_CIPHERTEXT_SIZE = ( - 32 + // pkd_new - 32 + // esk - NOTEENCRYPTION_AUTH_BYTES); - /** * A shielded output to a transaction. It contains data that describes an Output transfer. */ class OutputDescription { public: - typedef std::array sapling_enc_ct_t; // TODO: Replace with actual type - typedef std::array sapling_out_ct_t; // TODO: Replace with actual type - uint256 cv; //!< A value commitment to the value of the output note. uint256 cm; //!< The note commitment for the output note. uint256 ephemeralKey; //!< A Jubjub public key. - sapling_enc_ct_t encCiphertext; //!< A ciphertext component for the encrypted output note. - sapling_out_ct_t outCiphertext; //!< A ciphertext component for the encrypted output note. + libzcash::SaplingEncCiphertext encCiphertext; //!< A ciphertext component for the encrypted output note. + libzcash::SaplingOutCiphertext outCiphertext; //!< A ciphertext component for the encrypted output note. libzcash::GrothProof zkproof; //!< A zero-knowledge proof using the output circuit. OutputDescription() { } From c03e22612d737881b2319ccece12f755401cd791 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 14 Jun 2018 12:21:28 -0600 Subject: [PATCH 4/6] Prevent nonce reuse in Sapling note encryption API. --- src/gtest/test_noteencryption.cpp | 29 +++++++++++++++++++++++++++++ src/zcash/NoteEncryption.cpp | 12 ++++++++++++ src/zcash/NoteEncryption.hpp | 5 ++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/gtest/test_noteencryption.cpp b/src/gtest/test_noteencryption.cpp index 6c22daeeb8f..522f26c5bc7 100644 --- a/src/gtest/test_noteencryption.cpp +++ b/src/gtest/test_noteencryption.cpp @@ -78,6 +78,35 @@ TEST(noteencryption, sapling_api) small_message ); + // Test nonce-reuse resistance of API + { + auto tmp_enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d); + + tmp_enc.encrypt_to_recipient( + pk_1.pk_d, + message + ); + + ASSERT_THROW(tmp_enc.encrypt_to_recipient( + pk_1.pk_d, + message + ), std::logic_error); + + tmp_enc.encrypt_to_ourselves( + sk.ovk, + cv_2, + cm_2, + small_message + ); + + ASSERT_THROW(tmp_enc.encrypt_to_ourselves( + sk.ovk, + cv_2, + cm_2, + small_message + ), std::logic_error); + } + // Try to decrypt auto plaintext_1 = *AttemptSaplingEncDecryption( ciphertext_1, diff --git a/src/zcash/NoteEncryption.cpp b/src/zcash/NoteEncryption.cpp index 27e8b0b88f9..a00999bc3df 100644 --- a/src/zcash/NoteEncryption.cpp +++ b/src/zcash/NoteEncryption.cpp @@ -121,6 +121,10 @@ boost::optional SaplingNoteEncryption::encrypt_to_recipien const SaplingEncPlaintext &message ) { + if (already_encrypted_enc) { + throw std::logic_error("already encrypted to the recipient using this key"); + } + uint256 dhsecret; if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) { @@ -143,6 +147,8 @@ boost::optional SaplingNoteEncryption::encrypt_to_recipien NULL, cipher_nonce, K ); + already_encrypted_enc = true; + return ciphertext; } @@ -188,6 +194,10 @@ SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves( const SaplingOutPlaintext &message ) { + if (already_encrypted_out) { + throw std::logic_error("already encrypted to the recipient using this key"); + } + // Construct the symmetric key unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; PRF_ock(K, ovk, cv, cm, epk); @@ -204,6 +214,8 @@ SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves( NULL, cipher_nonce, K ); + already_encrypted_out = true; + return ciphertext; } diff --git a/src/zcash/NoteEncryption.hpp b/src/zcash/NoteEncryption.hpp index 47fc93f7e05..2855925e7fa 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -32,7 +32,10 @@ class SaplingNoteEncryption { // Ephemeral secret key uint256 esk; - SaplingNoteEncryption(uint256 epk, uint256 esk) : epk(epk), esk(esk) { + bool already_encrypted_enc; + bool already_encrypted_out; + + SaplingNoteEncryption(uint256 epk, uint256 esk) : epk(epk), esk(esk), already_encrypted_enc(false), already_encrypted_out(false) { } From 4e1f2daa0dc762f517c5f05c452ebccca1c78427 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Mon, 18 Jun 2018 13:14:43 -0600 Subject: [PATCH 5/6] Add get_esk() function to Sapling note encryption. --- src/gtest/test_noteencryption.cpp | 7 +++++++ src/zcash/NoteEncryption.hpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/gtest/test_noteencryption.cpp b/src/gtest/test_noteencryption.cpp index 522f26c5bc7..db341d3f441 100644 --- a/src/gtest/test_noteencryption.cpp +++ b/src/gtest/test_noteencryption.cpp @@ -8,6 +8,7 @@ #include "zcash/prf.h" #include "zcash/Address.hpp" #include "crypto/sha256.h" +#include "librustzcash.h" class TestNoteDecryption : public ZCNoteDecryption { public: @@ -52,6 +53,12 @@ TEST(noteencryption, sapling_api) message ); auto epk_1 = enc.get_epk(); + { + uint256 test_epk; + uint256 test_esk = enc.get_esk(); + ASSERT_TRUE(librustzcash_sapling_ka_derivepublic(pk_1.d.begin(), test_esk.begin(), test_epk.begin())); + ASSERT_TRUE(test_epk == epk_1); + } auto cv_1 = random_uint256(); auto cm_1 = random_uint256(); auto out_ciphertext_1 = enc.encrypt_to_ourselves( diff --git a/src/zcash/NoteEncryption.hpp b/src/zcash/NoteEncryption.hpp index 2855925e7fa..cee0b21cb7d 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -58,6 +58,10 @@ class SaplingNoteEncryption { uint256 get_epk() const { return epk; } + + uint256 get_esk() const { + return esk; + } }; // Attempts to decrypt a Sapling note. This will not check that the contents From 7478876271cf7c11f14034a74e1330cd72f9991a Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 11 Jul 2018 15:48:41 -0600 Subject: [PATCH 6/6] Minor edits --- src/gtest/test_noteencryption.cpp | 4 ++-- src/zcash/NoteEncryption.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gtest/test_noteencryption.cpp b/src/gtest/test_noteencryption.cpp index db341d3f441..1aded18f208 100644 --- a/src/gtest/test_noteencryption.cpp +++ b/src/gtest/test_noteencryption.cpp @@ -19,7 +19,7 @@ class TestNoteDecryption : public ZCNoteDecryption { } }; -TEST(noteencryption, sapling_api) +TEST(noteencryption, SaplingApi) { using namespace libzcash; @@ -44,7 +44,7 @@ TEST(noteencryption, sapling_api) } // Invalid diversifier - ASSERT_FALSE(SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); + ASSERT_EQ(boost::none, SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); // Encrypt to pk_1 auto enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d); diff --git a/src/zcash/NoteEncryption.hpp b/src/zcash/NoteEncryption.hpp index cee0b21cb7d..82f8b2abf34 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -24,6 +24,7 @@ typedef std::array SaplingEncPlaint typedef std::array SaplingOutCiphertext; typedef std::array SaplingOutPlaintext; +//! This is not a thread-safe API. class SaplingNoteEncryption { protected: // Ephemeral public key