penumbra_sdk_transaction/plan/
memo.rs

1use anyhow::Context;
2use penumbra_sdk_keys::{symmetric::PayloadKey, Address};
3use penumbra_sdk_proto::{core::transaction::v1 as pb, DomainType};
4
5use rand::{CryptoRng, RngCore};
6
7use crate::memo::{MemoCiphertext, MemoPlaintext};
8
9#[derive(Clone, Debug)]
10pub struct MemoPlan {
11    pub plaintext: MemoPlaintext,
12    pub key: PayloadKey,
13}
14
15impl MemoPlan {
16    /// Create a new [`MemoPlan`].
17    pub fn new<R: CryptoRng + RngCore>(rng: &mut R, plaintext: MemoPlaintext) -> MemoPlan {
18        let key = PayloadKey::random_key(rng);
19        MemoPlan { plaintext, key }
20    }
21
22    /// Create a [`MemoCiphertext`] from the [`MemoPlan`].
23    pub fn memo(&self) -> anyhow::Result<MemoCiphertext> {
24        MemoCiphertext::encrypt(self.key.clone(), &self.plaintext)
25    }
26}
27
28impl DomainType for MemoPlan {
29    type Proto = pb::MemoPlan;
30}
31
32impl From<MemoPlan> for pb::MemoPlan {
33    fn from(msg: MemoPlan) -> Self {
34        let return_address = Some(msg.plaintext.return_address().into());
35        let text = msg.plaintext.text().to_owned();
36        Self {
37            plaintext: Some(pb::MemoPlaintext {
38                return_address,
39                text,
40            }),
41            key: msg.key.to_vec(),
42        }
43    }
44}
45
46impl TryFrom<pb::MemoPlan> for MemoPlan {
47    type Error = anyhow::Error;
48
49    fn try_from(msg: pb::MemoPlan) -> Result<Self, Self::Error> {
50        let sender: Address = msg
51            .plaintext
52            .clone()
53            .ok_or_else(|| anyhow::anyhow!("memo plan missing memo plaintext"))?
54            .return_address
55            .ok_or_else(|| anyhow::anyhow!("memo plaintext missing return address"))?
56            .try_into()
57            .context("return address malformed")?;
58
59        let text: String = msg
60            .plaintext
61            .ok_or_else(|| anyhow::anyhow!("memo plan missing memo plaintext"))?
62            .text;
63
64        let key = PayloadKey::try_from(msg.key.to_vec())?;
65
66        Ok(Self {
67            plaintext: MemoPlaintext::new(sender, text)?,
68            key,
69        })
70    }
71}