phoenix_core/keys/
view.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 crate::{keys::hash, SecretKey, StealthAddress};
8
9use dusk_bytes::{DeserializableSlice, Error, Serializable};
10use dusk_jubjub::{
11    JubJubAffine, JubJubExtended, JubJubScalar, GENERATOR_EXTENDED,
12};
13use subtle::{Choice, ConstantTimeEq};
14
15#[cfg(feature = "rkyv-impl")]
16use rkyv::{Archive, Deserialize, Serialize};
17
18/// Pair of a secret `a` and public `b·G`
19///
20/// The notes are encrypted against secret a, so this is used to decrypt the
21/// blinding factor and value
22#[derive(Clone, Copy, Debug, Eq)]
23#[cfg_attr(
24    feature = "rkyv-impl",
25    derive(Archive, Serialize, Deserialize),
26    archive_attr(derive(bytecheck::CheckBytes))
27)]
28pub struct ViewKey {
29    a: JubJubScalar,
30    B: JubJubExtended,
31}
32
33impl ConstantTimeEq for ViewKey {
34    fn ct_eq(&self, other: &Self) -> Choice {
35        self.a.ct_eq(&other.a) & self.B.ct_eq(&other.B)
36    }
37}
38
39impl PartialEq for ViewKey {
40    fn eq(&self, other: &Self) -> bool {
41        self.ct_eq(other).into()
42    }
43}
44
45impl ViewKey {
46    /// This method is used to construct a new `ViewKey` from the given
47    /// pair of secret `a` and public `b·G`.
48    pub fn new(a: JubJubScalar, B: JubJubExtended) -> Self {
49        Self { a, B }
50    }
51
52    /// Gets `a`
53    pub fn a(&self) -> &JubJubScalar {
54        &self.a
55    }
56
57    /// Gets `B` (`b·G`)
58    pub fn B(&self) -> &JubJubExtended {
59        &self.B
60    }
61
62    /// Checks `note_pk = H(R · a) · G + B`
63    pub fn owns(&self, stealth_address: &StealthAddress) -> bool {
64        let aR = stealth_address.R() * self.a();
65        let hash_aR = hash(&aR);
66        let hash_aR_G = GENERATOR_EXTENDED * hash_aR;
67        let note_pk = hash_aR_G + self.B();
68
69        stealth_address.note_pk().as_ref() == &note_pk
70    }
71}
72
73impl From<&SecretKey> for ViewKey {
74    fn from(sk: &SecretKey) -> Self {
75        let B = GENERATOR_EXTENDED * sk.b();
76
77        ViewKey::new(*sk.a(), B)
78    }
79}
80
81impl Serializable<64> for ViewKey {
82    type Error = Error;
83
84    fn to_bytes(&self) -> [u8; 64] {
85        let mut bytes = [0u8; 64];
86        bytes[..32].copy_from_slice(&self.a.to_bytes());
87        bytes[32..].copy_from_slice(&JubJubAffine::from(&self.B).to_bytes());
88        bytes
89    }
90
91    fn from_bytes(buf: &[u8; 64]) -> Result<Self, Self::Error> {
92        let a = JubJubScalar::from_slice(&buf[..32])?;
93        let B = JubJubExtended::from(JubJubAffine::from_slice(&buf[32..])?);
94
95        Ok(Self { a, B })
96    }
97}