penumbra_sdk_transaction/plan/
clue.rs1use decaf377_fmd::{Clue, Precision};
2use penumbra_sdk_keys::Address;
3use penumbra_sdk_proto::{core::transaction::v1 as pb, DomainType};
4
5use rand::{CryptoRng, RngCore};
6
7#[derive(Clone, Debug)]
8pub struct CluePlan {
9 pub address: Address,
10 pub precision: Precision,
11 pub rseed: [u8; 32],
12}
13
14impl CluePlan {
15 pub fn new<R: CryptoRng + RngCore>(
17 rng: &mut R,
18 address: Address,
19 precision: Precision,
20 ) -> CluePlan {
21 let mut rseed = [0u8; 32];
22 rng.fill_bytes(&mut rseed);
23 CluePlan {
24 address,
25 rseed,
26 precision,
27 }
28 }
29
30 pub fn clue(&self) -> Clue {
32 let clue_key = self.address.clue_key();
33 let expanded_clue_key = clue_key.expand_infallible();
34 expanded_clue_key
35 .create_clue_deterministic(self.precision, self.rseed)
36 .expect("can construct clue key")
37 }
38}
39
40impl DomainType for CluePlan {
41 type Proto = pb::CluePlan;
42}
43
44impl From<CluePlan> for pb::CluePlan {
45 fn from(msg: CluePlan) -> Self {
46 Self {
47 address: Some(msg.address.into()),
48 rseed: msg.rseed.to_vec(),
49 precision_bits: msg.precision.bits() as u64,
50 }
51 }
52}
53
54impl TryFrom<pb::CluePlan> for CluePlan {
55 type Error = anyhow::Error;
56 fn try_from(msg: pb::CluePlan) -> Result<Self, Self::Error> {
57 Ok(Self {
58 address: msg
59 .address
60 .ok_or_else(|| anyhow::anyhow!("missing address"))?
61 .try_into()?,
62 rseed: msg.rseed.as_slice().try_into()?,
63 precision: msg.precision_bits.try_into()?,
64 })
65 }
66}