wallet: Use `zcash_note_encryption` in `CWalletTx::RecoverSaplingNote`
This commit is contained in:
parent
2fd287e73b
commit
f5ed454f87
|
@ -1,7 +1,10 @@
|
|||
use group::GroupEncoding;
|
||||
use zcash_note_encryption::{Domain, EphemeralKeyBytes, ShieldedOutput, ENC_CIPHERTEXT_SIZE};
|
||||
use zcash_note_encryption::{
|
||||
try_output_recovery_with_ovk, Domain, EphemeralKeyBytes, ShieldedOutput, ENC_CIPHERTEXT_SIZE,
|
||||
};
|
||||
use zcash_primitives::{
|
||||
consensus::BlockHeight,
|
||||
keys::OutgoingViewingKey,
|
||||
memo::MemoBytes,
|
||||
sapling::{
|
||||
self,
|
||||
|
@ -44,6 +47,42 @@ pub(crate) fn try_sapling_note_decryption(
|
|||
}))
|
||||
}
|
||||
|
||||
/// Recovery of the full note plaintext by the sender.
|
||||
///
|
||||
/// Attempts to decrypt and validate the given shielded output using the given `ovk`.
|
||||
/// If successful, the corresponding note and memo are returned, along with the address to
|
||||
/// which the note was sent.
|
||||
///
|
||||
/// Implements [Zcash Protocol Specification section 4.19.3][decryptovk].
|
||||
///
|
||||
/// [decryptovk]: https://zips.z.cash/protocol/protocol.pdf#decryptovk
|
||||
pub(crate) fn try_sapling_output_recovery(
|
||||
network: &Network,
|
||||
height: u32,
|
||||
ovk: [u8; 32],
|
||||
output: SaplingShieldedOutput,
|
||||
) -> Result<Box<DecryptedSaplingOutput>, &'static str> {
|
||||
let domain = SaplingDomain::for_height(*network, BlockHeight::from_u32(height));
|
||||
|
||||
let cv = Option::from(jubjub::ExtendedPoint::from_bytes(&output.cv))
|
||||
.ok_or("Invalid output.cv passed to wallet::try_sapling_note_decryption()")?;
|
||||
|
||||
let (note, recipient, memo) = try_output_recovery_with_ovk(
|
||||
&domain,
|
||||
&OutgoingViewingKey(ovk),
|
||||
&output,
|
||||
&cv,
|
||||
&output.out_ciphertext,
|
||||
)
|
||||
.ok_or("Decryption failed")?;
|
||||
|
||||
Ok(Box::new(DecryptedSaplingOutput {
|
||||
note,
|
||||
recipient,
|
||||
memo,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parses and validates a Sapling incoming viewing key, and prepares it for decryption.
|
||||
pub(crate) fn parse_and_prepare_sapling_ivk(
|
||||
raw_ivk: &[u8; 32],
|
||||
|
|
|
@ -23,7 +23,8 @@ use zcash_primitives::{
|
|||
|
||||
use crate::{
|
||||
note_encryption::{
|
||||
parse_and_prepare_sapling_ivk, try_sapling_note_decryption, DecryptedSaplingOutput,
|
||||
parse_and_prepare_sapling_ivk, try_sapling_note_decryption, try_sapling_output_recovery,
|
||||
DecryptedSaplingOutput,
|
||||
},
|
||||
params::{network, Network},
|
||||
};
|
||||
|
@ -32,9 +33,11 @@ use crate::{
|
|||
pub(crate) mod ffi {
|
||||
#[namespace = "wallet"]
|
||||
pub(crate) struct SaplingShieldedOutput {
|
||||
cv: [u8; 32],
|
||||
cmu: [u8; 32],
|
||||
ephemeral_key: [u8; 32],
|
||||
enc_ciphertext: [u8; 580],
|
||||
out_ciphertext: [u8; 80],
|
||||
}
|
||||
|
||||
#[namespace = "wallet"]
|
||||
|
@ -69,6 +72,12 @@ pub(crate) mod ffi {
|
|||
raw_ivk: &[u8; 32],
|
||||
output: SaplingShieldedOutput,
|
||||
) -> Result<Box<DecryptedSaplingOutput>>;
|
||||
fn try_sapling_output_recovery(
|
||||
network: &Network,
|
||||
height: u32,
|
||||
ovk: [u8; 32],
|
||||
output: SaplingShieldedOutput,
|
||||
) -> Result<Box<DecryptedSaplingOutput>>;
|
||||
|
||||
type DecryptedSaplingOutput;
|
||||
fn note_value(self: &DecryptedSaplingOutput) -> u64;
|
||||
|
|
|
@ -4253,7 +4253,6 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
|||
}
|
||||
};
|
||||
|
||||
auto& consensusParams = Params().GetConsensus();
|
||||
KeyIO keyIO(Params());
|
||||
// Sprout spends
|
||||
for (size_t i = 0; i < wtx.vJoinSplit.size(); ++i) {
|
||||
|
@ -4422,7 +4421,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
|||
isOutgoing = false;
|
||||
} else {
|
||||
// Try recovering the output
|
||||
auto recovered = wtx.RecoverSaplingNote(consensusParams, op, ovks);
|
||||
auto recovered = wtx.RecoverSaplingNote(Params(), op, ovks);
|
||||
if (recovered) {
|
||||
notePt = recovered->first;
|
||||
pa = recovered->second;
|
||||
|
|
|
@ -3787,9 +3787,11 @@ std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> CWallet::FindMySap
|
|||
height,
|
||||
ivk.GetRawBytes(),
|
||||
{
|
||||
output.cv.GetRawBytes(),
|
||||
output.cmu.GetRawBytes(),
|
||||
output.ephemeralKey.GetRawBytes(),
|
||||
output.encCiphertext,
|
||||
output.outCiphertext,
|
||||
});
|
||||
|
||||
SaplingPaymentAddress address(
|
||||
|
@ -4319,9 +4321,11 @@ std::optional<std::pair<
|
|||
params.GetConsensus().vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight,
|
||||
nd.ivk.GetRawBytes(),
|
||||
{
|
||||
output.cv.GetRawBytes(),
|
||||
output.cmu.GetRawBytes(),
|
||||
output.ephemeralKey.GetRawBytes(),
|
||||
output.encCiphertext,
|
||||
output.outCiphertext,
|
||||
});
|
||||
|
||||
return SaplingNotePlaintext::from_rust(std::move(decrypted));
|
||||
|
@ -4332,35 +4336,29 @@ std::optional<std::pair<
|
|||
|
||||
std::optional<std::pair<
|
||||
SaplingNotePlaintext,
|
||||
SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(const Consensus::Params& params, SaplingOutPoint op, std::set<uint256>& ovks) const
|
||||
SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(const CChainParams& params, SaplingOutPoint op, std::set<uint256>& ovks) const
|
||||
{
|
||||
auto output = this->vShieldedOutput[op.n];
|
||||
|
||||
for (auto ovk : ovks) {
|
||||
auto outPt = SaplingOutgoingPlaintext::decrypt(
|
||||
output.outCiphertext,
|
||||
ovk,
|
||||
output.cv,
|
||||
output.cmu,
|
||||
output.ephemeralKey);
|
||||
if (!outPt) {
|
||||
try {
|
||||
auto decrypted = wallet::try_sapling_output_recovery(
|
||||
*params.RustNetwork(),
|
||||
// Canopy activation is inside the ZIP 212 grace period.
|
||||
params.GetConsensus().vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight,
|
||||
ovk.GetRawBytes(),
|
||||
{
|
||||
output.cv.GetRawBytes(),
|
||||
output.cmu.GetRawBytes(),
|
||||
output.ephemeralKey.GetRawBytes(),
|
||||
output.encCiphertext,
|
||||
output.outCiphertext,
|
||||
});
|
||||
|
||||
return SaplingNotePlaintext::from_rust(std::move(decrypted));
|
||||
} catch (const rust::Error &e) {
|
||||
// Try decrypting with the next ovk
|
||||
continue;
|
||||
}
|
||||
|
||||
auto maybe_pt = SaplingNotePlaintext::decrypt(
|
||||
params,
|
||||
// Canopy activation is inside the ZIP 212 grace period.
|
||||
params.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight,
|
||||
output.encCiphertext,
|
||||
output.ephemeralKey,
|
||||
outPt->esk,
|
||||
outPt->pk_d,
|
||||
output.cmu);
|
||||
assert(static_cast<bool>(maybe_pt));
|
||||
auto notePt = maybe_pt.value();
|
||||
|
||||
return std::make_pair(notePt, SaplingPaymentAddress(notePt.d, outPt->pk_d));
|
||||
}
|
||||
|
||||
// Couldn't recover with any of the provided OutgoingViewingKeys
|
||||
|
|
|
@ -686,7 +686,7 @@ public:
|
|||
*/
|
||||
std::optional<std::pair<
|
||||
libzcash::SaplingNotePlaintext,
|
||||
libzcash::SaplingPaymentAddress>> RecoverSaplingNote(const Consensus::Params& params,
|
||||
libzcash::SaplingPaymentAddress>> RecoverSaplingNote(const CChainParams& params,
|
||||
SaplingOutPoint op, std::set<uint256>& ovks) const;
|
||||
OrchardActions RecoverOrchardActions(const std::vector<uint256>& ovks) const;
|
||||
|
||||
|
|
Loading…
Reference in New Issue