Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sapling note encryption implementation #3324

Merged
merged 6 commits into from Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/gtest/test_noteencryption.cpp
Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we change this line to pk_2.pk_d the call still throws the same error due to already_encrypted_enc having been set, so we're not really testing nonce reuse, but the fact that encrypt_to_recipient can be only called once successfully.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the intent of the nonce reuse resistant API; if you call encrypt_to_recipient twice (which you should never do, ephemeral keys are not reused) then the ChaCha20 nonce will be reused, which we cannot allow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Note that encrypt_to_recipient could be called twice because the method is not thread safe with regards to the boolean flag. Perhaps document that the note encryption class should not be used by multiple threads concurrently.

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,
Expand Down
12 changes: 12 additions & 0 deletions src/zcash/NoteEncryption.cpp
Expand Up @@ -121,6 +121,10 @@ boost::optional<SaplingEncCiphertext> 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())) {
Expand All @@ -143,6 +147,8 @@ boost::optional<SaplingEncCiphertext> SaplingNoteEncryption::encrypt_to_recipien
NULL, cipher_nonce, K
);

already_encrypted_enc = true;

return ciphertext;
}

Expand Down Expand Up @@ -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);
Expand All @@ -204,6 +214,8 @@ SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves(
NULL, cipher_nonce, K
);

already_encrypted_out = true;

return ciphertext;
}

Expand Down
5 changes: 4 additions & 1 deletion src/zcash/NoteEncryption.hpp
Expand Up @@ -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) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove redundant line of whitespace, and have { } on the same line after function sig.

}

Expand Down