orchard/address.rs
1use subtle::CtOption;
2
3use crate::{
4 keys::{DiversifiedTransmissionKey, Diversifier},
5 spec::{diversify_hash, NonIdentityPallasPoint},
6};
7
8/// A shielded payment address.
9///
10/// # Examples
11///
12/// ```
13/// use orchard::keys::{SpendingKey, FullViewingKey, Scope};
14///
15/// let sk = SpendingKey::from_bytes([7; 32]).unwrap();
16/// let address = FullViewingKey::from(&sk).address_at(0u32, Scope::External);
17/// ```
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct Address {
20 d: Diversifier,
21 pk_d: DiversifiedTransmissionKey,
22}
23
24impl Address {
25 pub(crate) fn from_parts(d: Diversifier, pk_d: DiversifiedTransmissionKey) -> Self {
26 // We assume here that pk_d is correctly-derived from d. We ensure this for
27 // internal APIs. For parsing from raw byte encodings, we assume that users aren't
28 // modifying internals of encoded address formats. If they do, that can result in
29 // lost funds, but we can't defend against that from here.
30 Address { d, pk_d }
31 }
32
33 /// Returns the [`Diversifier`] for this `Address`.
34 pub fn diversifier(&self) -> Diversifier {
35 self.d
36 }
37
38 /// Returns the diversified base point for this address.
39 pub fn g_d(&self) -> NonIdentityPallasPoint {
40 diversify_hash(self.d.as_array())
41 }
42
43 /// Returns the diversified transmission key for this address.
44 pub fn pk_d(&self) -> &DiversifiedTransmissionKey {
45 &self.pk_d
46 }
47
48 /// Serializes this address to its "raw" encoding as specified in [Zcash Protocol Spec § 5.6.4.2: Orchard Raw Payment Addresses][orchardpaymentaddrencoding]
49 ///
50 /// [orchardpaymentaddrencoding]: https://zips.z.cash/protocol/protocol.pdf#orchardpaymentaddrencoding
51 pub fn to_raw_address_bytes(&self) -> [u8; 43] {
52 let mut result = [0u8; 43];
53 result[..11].copy_from_slice(self.d.as_array());
54 result[11..].copy_from_slice(&self.pk_d.to_bytes());
55 result
56 }
57
58 /// Parse an address from its "raw" encoding as specified in [Zcash Protocol Spec § 5.6.4.2: Orchard Raw Payment Addresses][orchardpaymentaddrencoding]
59 ///
60 /// [orchardpaymentaddrencoding]: https://zips.z.cash/protocol/protocol.pdf#orchardpaymentaddrencoding
61 pub fn from_raw_address_bytes(bytes: &[u8; 43]) -> CtOption<Self> {
62 DiversifiedTransmissionKey::from_bytes(bytes[11..].try_into().unwrap()).map(|pk_d| {
63 let d = Diversifier::from_bytes(bytes[..11].try_into().unwrap());
64 Self::from_parts(d, pk_d)
65 })
66 }
67}
68
69/// Generators for property testing.
70#[cfg(any(test, feature = "test-dependencies"))]
71#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
72pub mod testing {
73 use proptest::prelude::*;
74
75 use crate::keys::{
76 testing::{arb_diversifier_index, arb_spending_key},
77 FullViewingKey, Scope,
78 };
79
80 use super::Address;
81
82 prop_compose! {
83 /// Generates an arbitrary payment address.
84 pub(crate) fn arb_address()(sk in arb_spending_key(), j in arb_diversifier_index()) -> Address {
85 let fvk = FullViewingKey::from(&sk);
86 fvk.address_at(j, Scope::External)
87 }
88 }
89}