penumbra_sdk_tct/internal/
proof.rs1use std::fmt::Debug;
7
8use crate::prelude::*;
9
10#[derive(Derivative)]
12#[derivative(
13 Debug(bound = "<Tree::Height as path::Path>::Path: Debug"),
14 Clone(bound = "<Tree::Height as path::Path>::Path: Clone"),
15 PartialEq(bound = "<Tree::Height as path::Path>::Path: PartialEq"),
16 Eq(bound = "<Tree::Height as path::Path>::Path: Eq")
17)]
18pub struct Proof<Tree: Height> {
19 pub(crate) position: u64,
20 pub(crate) auth_path: AuthPath<Tree>,
21 pub(crate) leaf: StateCommitment,
22}
23
24impl<Tree: Height> Proof<Tree> {
25 pub fn verify(&self, root: Hash) -> Result<(), VerifyError> {
29 if root == self.root() {
30 Ok(())
31 } else {
32 Err(VerifyError { root })
33 }
34 }
35
36 pub fn root(&self) -> Hash {
38 Tree::Height::root(&self.auth_path, self.position, Hash::of(self.leaf))
39 }
40
41 pub fn index(&self) -> u64 {
43 self.position
44 }
45
46 pub fn auth_path(&self) -> &AuthPath<Tree> {
49 &self.auth_path
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
55#[error("invalid inclusion proof for root hash {root:?}")]
56pub struct VerifyError {
57 root: Hash,
58}
59
60impl VerifyError {
61 pub fn root(&self) -> Hash {
63 self.root
64 }
65}
66
67#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
69#[error("could not decode proof")]
70pub struct ProofDecodeError;
71
72use decaf377::Fq;
73use penumbra_sdk_proto::penumbra::crypto::tct::v1 as pb;
74
75impl<Tree: Height> From<Proof<Tree>> for pb::StateCommitmentProof
76where
77 Vec<pb::MerklePathChunk>: From<AuthPath<Tree>>,
78{
79 fn from(proof: Proof<Tree>) -> Self {
80 Self {
81 position: proof.position,
82 auth_path: proof.auth_path.into(),
83 note_commitment: Some(proof.leaf.into()),
84 }
85 }
86}
87
88impl<Tree: Height> TryFrom<pb::StateCommitmentProof> for Proof<Tree>
89where
90 AuthPath<Tree>: TryFrom<Vec<pb::MerklePathChunk>>,
91{
92 type Error = ProofDecodeError;
93
94 fn try_from(proof: pb::StateCommitmentProof) -> Result<Self, Self::Error> {
95 let position = proof.position;
96 let auth_path = proof.auth_path.try_into().map_err(|_| ProofDecodeError)?;
97 let leaf = StateCommitment(
98 Fq::from_bytes_checked(
99 &proof
100 .note_commitment
101 .ok_or(ProofDecodeError)?
102 .inner
103 .try_into()
104 .map_err(|_| ProofDecodeError)?,
105 )
106 .map_err(|_| ProofDecodeError)?,
107 );
108
109 Ok(Self {
110 position,
111 auth_path,
112 leaf,
113 })
114 }
115}