phoenix_core/
stealth_address.rs1use dusk_jubjub::{JubJubAffine, JubJubExtended};
8use jubjub_schnorr::PublicKey as NotePublicKey;
9
10use dusk_bytes::{DeserializableSlice, Error, Serializable};
11
12use subtle::{Choice, ConstantTimeEq};
13
14#[cfg(feature = "rkyv-impl")]
15use rkyv::{Archive, Deserialize, Serialize};
16
17#[derive(Default, Debug, Clone, Copy, Eq)]
22#[cfg_attr(
23 feature = "rkyv-impl",
24 derive(Archive, Serialize, Deserialize),
25 archive_attr(derive(bytecheck::CheckBytes))
26)]
27pub struct StealthAddress {
28 pub(crate) R: JubJubExtended,
29 pub(crate) note_pk: NotePublicKey,
30}
31
32impl StealthAddress {
33 pub const fn from_raw_unchecked(
43 R: JubJubExtended,
44 note_pk: NotePublicKey,
45 ) -> Self {
46 Self { R, note_pk }
47 }
48
49 pub const fn R(&self) -> &JubJubExtended {
51 &self.R
52 }
53
54 pub const fn note_pk(&self) -> &NotePublicKey {
56 &self.note_pk
57 }
58}
59
60impl ConstantTimeEq for StealthAddress {
61 fn ct_eq(&self, other: &Self) -> Choice {
62 self.note_pk().as_ref().ct_eq(other.note_pk().as_ref())
63 & self.R.ct_eq(&other.R)
64 }
65}
66
67impl PartialEq for StealthAddress {
68 fn eq(&self, other: &Self) -> bool {
69 self.ct_eq(other).into()
70 }
71}
72
73impl Serializable<64> for StealthAddress {
74 type Error = Error;
75 fn to_bytes(&self) -> [u8; Self::SIZE] {
77 let mut bytes = [0u8; Self::SIZE];
78 bytes[..32].copy_from_slice(&JubJubAffine::from(self.R).to_bytes());
79 bytes[32..].copy_from_slice(
80 &JubJubAffine::from(self.note_pk().as_ref()).to_bytes(),
81 );
82 bytes
83 }
84
85 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Error> {
87 let R = JubJubExtended::from(JubJubAffine::from_slice(&bytes[..32])?);
88 let note_pk =
89 JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?);
90 let note_pk = NotePublicKey::from_raw_unchecked(note_pk);
91
92 Ok(StealthAddress { R, note_pk })
93 }
94}