zebra_chain/primitives/viewing_key/
sapling.rs

1//! Defines types and implements methods for parsing Sapling viewing keys and converting them to `zebra-chain` types
2
3use sapling_crypto::keys::{FullViewingKey as SaplingFvk, SaplingIvk};
4use zcash_client_backend::{
5    encoding::decode_extended_full_viewing_key,
6    keys::sapling::DiversifiableFullViewingKey as SaplingDfvk,
7};
8use zcash_protocol::constants::*;
9
10use crate::parameters::Network;
11
12/// A Zcash Sapling viewing key
13#[derive(Debug, Clone)]
14pub enum SaplingViewingKey {
15    /// An incoming viewing key for Sapling
16    Ivk(Box<SaplingIvk>),
17
18    /// A full viewing key for Sapling
19    Fvk(Box<SaplingFvk>),
20
21    /// A diversifiable full viewing key for Sapling
22    Dfvk(Box<SaplingDfvk>),
23}
24
25impl SaplingViewingKey {
26    /// Accepts an encoded Sapling extended full viewing key to decode
27    ///
28    /// Returns a [`SaplingViewingKey::Dfvk`] if successful, or None otherwise
29    fn parse_extended_full_viewing_key(sapling_key: &str, network: &Network) -> Option<Self> {
30        decode_extended_full_viewing_key(network.sapling_efvk_hrp(), sapling_key)
31            // this should fail often, so a debug-level log is okay
32            .map_err(|err| debug!(?err, "could not decode Sapling extended full viewing key"))
33            .ok()
34            .map(|efvk| Box::new(efvk.to_diversifiable_full_viewing_key()))
35            .map(Self::Dfvk)
36    }
37
38    /// Accepts an encoded Sapling diversifiable full viewing key to decode
39    ///
40    /// Returns a [`SaplingViewingKey::Dfvk`] if successful, or None otherwise
41    fn parse_diversifiable_full_viewing_key(
42        _sapling_key: &str,
43        _network: &Network,
44    ) -> Option<Self> {
45        // TODO: Parse Sapling diversifiable full viewing key
46        None
47    }
48
49    /// Accepts an encoded Sapling full viewing key to decode
50    ///
51    /// Returns a [`SaplingViewingKey::Fvk`] if successful, or None otherwise
52    fn parse_full_viewing_key(_sapling_key: &str, _network: &Network) -> Option<Self> {
53        // TODO: Parse Sapling full viewing key
54        None
55    }
56
57    /// Accepts an encoded Sapling incoming viewing key to decode
58    ///
59    /// Returns a [`SaplingViewingKey::Ivk`] if successful, or None otherwise
60    fn parse_incoming_viewing_key(_sapling_key: &str, _network: &Network) -> Option<Self> {
61        // TODO: Parse Sapling incoming viewing key
62        None
63    }
64
65    /// Accepts an encoded Sapling viewing key to decode
66    ///
67    /// Returns a [`SaplingViewingKey`] if successful, or None otherwise
68    pub(super) fn parse(key: &str, network: &Network) -> Option<Self> {
69        // TODO: Try types with prefixes first if some don't have prefixes?
70        Self::parse_extended_full_viewing_key(key, network)
71            .or_else(|| Self::parse_diversifiable_full_viewing_key(key, network))
72            .or_else(|| Self::parse_full_viewing_key(key, network))
73            .or_else(|| Self::parse_incoming_viewing_key(key, network))
74    }
75}
76
77impl Network {
78    /// Returns the human-readable prefix for an Zcash Sapling extended full viewing key
79    /// for this network.
80    pub fn sapling_efvk_hrp(&self) -> &'static str {
81        if self.is_a_test_network() {
82            // Assume custom testnets have the same HRP
83            //
84            // TODO: add the regtest HRP here
85            testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY
86        } else {
87            mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY
88        }
89    }
90}