diff --git a/src/gtest/test_noteencryption.cpp b/src/gtest/test_noteencryption.cpp index 6c22daeeb..522f26c5b 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 27e8b0b88..a00999bc3 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 47fc93f7e..2855925e7 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -32,7 +32,10 @@ protected: // 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) { }