use dusk_jubjub::{JubJubAffine, JubJubExtended};
use jubjub_schnorr::PublicKey as NotePublicKey;
use dusk_bytes::{DeserializableSlice, Error, Serializable};
use subtle::{Choice, ConstantTimeEq};
#[cfg(feature = "rkyv-impl")]
use rkyv::{Archive, Deserialize, Serialize};
#[derive(Default, Debug, Clone, Copy, Eq)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct StealthAddress {
pub(crate) R: JubJubExtended,
pub(crate) note_pk: NotePublicKey,
}
impl StealthAddress {
pub const fn from_raw_unchecked(
R: JubJubExtended,
note_pk: NotePublicKey,
) -> Self {
Self { R, note_pk }
}
pub const fn R(&self) -> &JubJubExtended {
&self.R
}
pub const fn note_pk(&self) -> &NotePublicKey {
&self.note_pk
}
}
impl ConstantTimeEq for StealthAddress {
fn ct_eq(&self, other: &Self) -> Choice {
self.note_pk().as_ref().ct_eq(other.note_pk().as_ref())
& self.R.ct_eq(&other.R)
}
}
impl PartialEq for StealthAddress {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl Serializable<64> for StealthAddress {
type Error = Error;
fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut bytes = [0u8; Self::SIZE];
bytes[..32].copy_from_slice(&JubJubAffine::from(self.R).to_bytes());
bytes[32..].copy_from_slice(
&JubJubAffine::from(self.note_pk().as_ref()).to_bytes(),
);
bytes
}
fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Error> {
let R = JubJubExtended::from(JubJubAffine::from_slice(&bytes[..32])?);
let note_pk =
JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?);
let note_pk = NotePublicKey::from_raw_unchecked(note_pk);
Ok(StealthAddress { R, note_pk })
}
}