phoenix_core/keys/
public.rs1use crate::{keys::hash, SecretKey, StealthAddress, ViewKey};
8
9use dusk_jubjub::{JubJubAffine, JubJubExtended, JubJubScalar};
10
11#[cfg(feature = "rkyv-impl")]
12use rkyv::{Archive, Deserialize, Serialize};
13
14use dusk_bytes::{DeserializableSlice, Error, Serializable};
15use dusk_jubjub::GENERATOR_EXTENDED;
16use subtle::{Choice, ConstantTimeEq};
17
18#[derive(Debug, Clone, Copy, Eq)]
20#[cfg_attr(
21 feature = "rkyv-impl",
22 derive(Archive, Serialize, Deserialize),
23 archive_attr(derive(bytecheck::CheckBytes))
24)]
25pub struct PublicKey {
26 A: JubJubExtended,
27 B: JubJubExtended,
28}
29
30impl PublicKey {
31 pub fn new(A: JubJubExtended, B: JubJubExtended) -> Self {
34 Self { A, B }
35 }
36
37 pub fn A(&self) -> &JubJubExtended {
39 &self.A
40 }
41
42 pub fn B(&self) -> &JubJubExtended {
44 &self.B
45 }
46
47 pub fn gen_stealth_address(&self, r: &JubJubScalar) -> StealthAddress {
49 let G = GENERATOR_EXTENDED;
50 let R = G * r;
51
52 let rA = self.A * r;
53 let rA = hash(&rA);
54 let rA = G * rA;
55
56 let note_pk = rA + self.B;
57 let note_pk = note_pk.into();
58
59 StealthAddress { R, note_pk }
60 }
61}
62
63impl ConstantTimeEq for PublicKey {
64 fn ct_eq(&self, other: &Self) -> Choice {
65 self.A.ct_eq(&other.A) & self.B.ct_eq(&other.B)
66 }
67}
68
69impl PartialEq for PublicKey {
70 fn eq(&self, other: &Self) -> bool {
71 self.ct_eq(other).into()
72 }
73}
74
75impl From<&SecretKey> for PublicKey {
76 fn from(sk: &SecretKey) -> Self {
77 let A = GENERATOR_EXTENDED * sk.a();
78 let B = GENERATOR_EXTENDED * sk.b();
79
80 PublicKey::new(A, B)
81 }
82}
83
84impl From<ViewKey> for PublicKey {
85 fn from(vk: ViewKey) -> Self {
86 Self::from(&vk)
87 }
88}
89
90impl From<&ViewKey> for PublicKey {
91 fn from(vk: &ViewKey) -> Self {
92 let A = GENERATOR_EXTENDED * vk.a();
93
94 PublicKey::new(A, *vk.B())
95 }
96}
97
98impl Serializable<64> for PublicKey {
99 type Error = Error;
100
101 fn to_bytes(&self) -> [u8; Self::SIZE] {
102 let mut bytes = [0u8; Self::SIZE];
103 bytes[..32].copy_from_slice(&JubJubAffine::from(self.A).to_bytes());
104 bytes[32..].copy_from_slice(&JubJubAffine::from(self.B).to_bytes());
105 bytes
106 }
107
108 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
109 let A = JubJubExtended::from(JubJubAffine::from_slice(&bytes[..32])?);
110 let B = JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?);
111
112 Ok(Self { A, B })
113 }
114}