Implement Sapling note decryption using full viewing key.
This commit is contained in:
@@ -111,6 +111,25 @@ TEST(noteencryption, NotePlaintext)
|
|||||||
|
|
||||||
ASSERT_TRUE(decrypted_out_ct_unwrapped.pk_d == out_pt.pk_d);
|
ASSERT_TRUE(decrypted_out_ct_unwrapped.pk_d == out_pt.pk_d);
|
||||||
ASSERT_TRUE(decrypted_out_ct_unwrapped.esk == out_pt.esk);
|
ASSERT_TRUE(decrypted_out_ct_unwrapped.esk == out_pt.esk);
|
||||||
|
|
||||||
|
// Test sender can decrypt the note ciphertext.
|
||||||
|
foo = SaplingNotePlaintext::decryptUsingFullViewingKey(
|
||||||
|
ct,
|
||||||
|
epk,
|
||||||
|
decrypted_out_ct_unwrapped.esk,
|
||||||
|
decrypted_out_ct_unwrapped.pk_d
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!foo) {
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
bar = foo.get();
|
||||||
|
|
||||||
|
ASSERT_TRUE(bar.value() == pt.value());
|
||||||
|
ASSERT_TRUE(bar.memo() == pt.memo());
|
||||||
|
ASSERT_TRUE(bar.d == pt.d);
|
||||||
|
ASSERT_TRUE(bar.rcm == pt.rcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(noteencryption, SaplingApi)
|
TEST(noteencryption, SaplingApi)
|
||||||
|
|||||||
@@ -208,6 +208,30 @@ boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decryptUsingFullViewingKey(
|
||||||
|
const SaplingEncCiphertext &ciphertext,
|
||||||
|
const uint256 &epk,
|
||||||
|
const uint256 &esk,
|
||||||
|
const uint256 &pk_d
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto pt = AttemptSaplingEncDecryptionUsingFullViewingKey(ciphertext, epk, esk, pk_d);
|
||||||
|
if (!pt) {
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize from the plaintext
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << pt.get();
|
||||||
|
|
||||||
|
SaplingNotePlaintext ret;
|
||||||
|
ss >> ret;
|
||||||
|
|
||||||
|
assert(ss.size() == 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
boost::optional<SaplingNotePlaintextEncryptionResult> SaplingNotePlaintext::encrypt(const uint256& pk_d) const
|
boost::optional<SaplingNotePlaintextEncryptionResult> SaplingNotePlaintext::encrypt(const uint256& pk_d) const
|
||||||
{
|
{
|
||||||
// Get the encryptor
|
// Get the encryptor
|
||||||
|
|||||||
@@ -133,6 +133,13 @@ public:
|
|||||||
const uint256 &epk
|
const uint256 &epk
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static boost::optional<SaplingNotePlaintext> decryptUsingFullViewingKey(
|
||||||
|
const SaplingEncCiphertext &ciphertext,
|
||||||
|
const uint256 &epk,
|
||||||
|
const uint256 &esk,
|
||||||
|
const uint256 &pk_d
|
||||||
|
);
|
||||||
|
|
||||||
boost::optional<SaplingNote> note(const SaplingIncomingViewingKey& ivk) const;
|
boost::optional<SaplingNote> note(const SaplingIncomingViewingKey& ivk) const;
|
||||||
|
|
||||||
virtual ~SaplingNotePlaintext() {}
|
virtual ~SaplingNotePlaintext() {}
|
||||||
|
|||||||
@@ -187,6 +187,43 @@ boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
|
|||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryptionUsingFullViewingKey (
|
||||||
|
const SaplingEncCiphertext &ciphertext,
|
||||||
|
const uint256 &epk,
|
||||||
|
const uint256 &esk,
|
||||||
|
const uint256 &pk_d
|
||||||
|
)
|
||||||
|
{
|
||||||
|
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] = {};
|
||||||
|
|
||||||
|
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(
|
SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves(
|
||||||
const uint256 &ovk,
|
const uint256 &ovk,
|
||||||
const uint256 &cv,
|
const uint256 &cv,
|
||||||
|
|||||||
@@ -73,6 +73,15 @@ boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
|
|||||||
const uint256 &epk
|
const uint256 &epk
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Attempts to decrypt a Sapling note using full viewing key.
|
||||||
|
// This will not check that the contents of the ciphertext are correct.
|
||||||
|
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryptionUsingFullViewingKey (
|
||||||
|
const SaplingEncCiphertext &ciphertext,
|
||||||
|
const uint256 &epk,
|
||||||
|
const uint256 &esk,
|
||||||
|
const uint256 &pk_d
|
||||||
|
);
|
||||||
|
|
||||||
// Attempts to decrypt a Sapling note. This will not check that the contents
|
// Attempts to decrypt a Sapling note. This will not check that the contents
|
||||||
// of the ciphertext are correct.
|
// of the ciphertext are correct.
|
||||||
boost::optional<SaplingOutPlaintext> AttemptSaplingOutDecryption(
|
boost::optional<SaplingOutPlaintext> AttemptSaplingOutDecryption(
|
||||||
|
|||||||
Reference in New Issue
Block a user