penumbra_sdk_custody/
pre_auth.rs

1use penumbra_sdk_proto::{custody::v1 as pb, DomainType};
2use serde::{Deserialize, Serialize};
3
4/// A pre-authorization packet.  This allows a custodian to delegate (partial)
5/// signing authority to other authorization mechanisms.  Details of how a
6/// custodian manages those keys are out-of-scope for the custody protocol and
7/// are custodian-specific.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(try_from = "pb::PreAuthorization", into = "pb::PreAuthorization")]
10pub enum PreAuthorization {
11    Ed25519(Ed25519),
12}
13
14/// An Ed25519-based preauthorization, containing an Ed25519 signature over the
15/// `TransactionPlan`.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(
18    try_from = "pb::pre_authorization::Ed25519",
19    into = "pb::pre_authorization::Ed25519"
20)]
21pub struct Ed25519 {
22    /// The verification key used to pre-authorize the `TransactionPlan`.
23    pub vk: ed25519_consensus::VerificationKey,
24    /// An Ed25519 signature over the `TransactionPlan`.
25    pub sig: ed25519_consensus::Signature,
26}
27
28impl Ed25519 {
29    /// Verifies the provided `TransactionPlan`.
30    pub fn verify(&self, message: impl AsRef<[u8]>) -> anyhow::Result<()> {
31        let bytes = message.as_ref();
32        self.vk.verify(&self.sig, &bytes).map_err(Into::into)
33    }
34}
35
36impl DomainType for PreAuthorization {
37    type Proto = pb::PreAuthorization;
38}
39
40impl TryFrom<pb::PreAuthorization> for PreAuthorization {
41    type Error = anyhow::Error;
42    fn try_from(value: pb::PreAuthorization) -> Result<Self, Self::Error> {
43        Ok(match value.pre_authorization {
44            Some(pb::pre_authorization::PreAuthorization::Ed25519(ed)) => {
45                Self::Ed25519(ed.try_into()?)
46            }
47            None => {
48                anyhow::bail!("missing pre-authorization");
49            }
50        })
51    }
52}
53
54impl From<PreAuthorization> for pb::PreAuthorization {
55    fn from(value: PreAuthorization) -> pb::PreAuthorization {
56        Self {
57            pre_authorization: Some(match value {
58                PreAuthorization::Ed25519(ed) => {
59                    pb::pre_authorization::PreAuthorization::Ed25519(ed.into())
60                }
61            }),
62        }
63    }
64}
65
66impl DomainType for Ed25519 {
67    type Proto = pb::pre_authorization::Ed25519;
68}
69
70impl TryFrom<pb::pre_authorization::Ed25519> for Ed25519 {
71    type Error = anyhow::Error;
72    fn try_from(value: pb::pre_authorization::Ed25519) -> Result<Self, Self::Error> {
73        Ok(Self {
74            vk: value.vk.as_slice().try_into()?,
75            sig: value.sig.as_slice().try_into()?,
76        })
77    }
78}
79
80impl From<Ed25519> for pb::pre_authorization::Ed25519 {
81    fn from(value: Ed25519) -> pb::pre_authorization::Ed25519 {
82        Self {
83            vk: value.vk.to_bytes().into(),
84            sig: value.sig.to_bytes().into(),
85        }
86    }
87}