phoenix_core/
stealth_address.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use 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/// To obfuscate the identity of the participants, we utilizes a Stealth Address
18/// system.
19/// A `StealthAddress` is composed by a one-time note-public-key (the actual
20/// address) and a random point `R`.
21#[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    /// Create a stealth address from its internal parts
34    ///
35    /// A stealth address is intended to be generated as the public counterpart
36    /// of a one time secret key. If the user opts to generate the
37    /// stealth address from points, there is no guarantee a secret one time
38    /// key counterpart will be known, and this stealth address will
39    /// not provide the required arguments to generate it.
40    ///
41    /// For additional information, check [PublicKey::from_raw_unchecked].
42    pub const fn from_raw_unchecked(
43        R: JubJubExtended,
44        note_pk: NotePublicKey,
45    ) -> Self {
46        Self { R, note_pk }
47    }
48
49    /// Gets the random point `R`
50    pub const fn R(&self) -> &JubJubExtended {
51        &self.R
52    }
53
54    /// Gets the `note_pk`
55    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    /// Encode the `StealthAddress` to an array of 64 bytes
76    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    /// Decode the `StealthAddress` from an array of 64 bytes
86    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}