sapling_crypto/
address.rs1use super::{
2 keys::{DiversifiedTransmissionKey, Diversifier},
3 note::{Note, Rseed},
4 value::NoteValue,
5};
6
7#[derive(Clone, Copy, Debug)]
15pub struct PaymentAddress {
16 pk_d: DiversifiedTransmissionKey,
17 diversifier: Diversifier,
18}
19
20impl PartialEq for PaymentAddress {
21 fn eq(&self, other: &Self) -> bool {
22 self.pk_d == other.pk_d && self.diversifier == other.diversifier
23 }
24}
25
26impl Eq for PaymentAddress {}
27
28impl PaymentAddress {
29 pub fn from_parts(diversifier: Diversifier, pk_d: DiversifiedTransmissionKey) -> Option<Self> {
36 diversifier.g_d()?;
38
39 Self::from_parts_unchecked(diversifier, pk_d)
40 }
41
42 pub(crate) fn from_parts_unchecked(
47 diversifier: Diversifier,
48 pk_d: DiversifiedTransmissionKey,
49 ) -> Option<Self> {
50 if pk_d.is_identity() {
51 None
52 } else {
53 Some(PaymentAddress { pk_d, diversifier })
54 }
55 }
56
57 pub fn from_bytes(bytes: &[u8; 43]) -> Option<Self> {
59 let diversifier = {
60 let mut tmp = [0; 11];
61 tmp.copy_from_slice(&bytes[0..11]);
62 Diversifier(tmp)
63 };
64
65 let pk_d = DiversifiedTransmissionKey::from_bytes(bytes[11..43].try_into().unwrap());
66 if pk_d.is_some().into() {
67 PaymentAddress::from_parts(diversifier, pk_d.unwrap())
69 } else {
70 None
71 }
72 }
73
74 pub fn to_bytes(&self) -> [u8; 43] {
76 let mut bytes = [0; 43];
77 bytes[0..11].copy_from_slice(&self.diversifier.0);
78 bytes[11..].copy_from_slice(&self.pk_d.to_bytes());
79 bytes
80 }
81
82 pub fn diversifier(&self) -> &Diversifier {
84 &self.diversifier
85 }
86
87 pub fn pk_d(&self) -> &DiversifiedTransmissionKey {
89 &self.pk_d
90 }
91
92 pub(crate) fn g_d(&self) -> jubjub::SubgroupPoint {
93 self.diversifier.g_d().expect("checked at construction")
94 }
95
96 pub fn create_note(&self, value: NoteValue, rseed: Rseed) -> Note {
97 Note::from_parts(*self, value, rseed)
98 }
99}
100
101#[cfg(any(test, feature = "test-dependencies"))]
102pub(super) mod testing {
103 use proptest::prelude::*;
104
105 use super::{
106 super::keys::{testing::arb_incoming_viewing_key, Diversifier, SaplingIvk},
107 PaymentAddress,
108 };
109
110 pub fn arb_payment_address() -> impl Strategy<Value = PaymentAddress> {
111 arb_incoming_viewing_key().prop_flat_map(|ivk: SaplingIvk| {
112 any::<[u8; 11]>().prop_filter_map(
113 "Sampled diversifier must generate a valid Sapling payment address.",
114 move |d| ivk.to_payment_address(Diversifier(d)),
115 )
116 })
117 }
118}