phoenix_core/keys/secret.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.
use crate::{keys::hash, StealthAddress};
use dusk_jubjub::{JubJubScalar, GENERATOR_EXTENDED};
use ff::Field;
use jubjub_schnorr::SecretKey as NoteSecretKey;
use zeroize::Zeroize;
#[cfg(feature = "rkyv-impl")]
use rkyv::{Archive, Deserialize, Serialize};
use dusk_bytes::{DeserializableSlice, Error, Serializable};
use rand::{CryptoRng, RngCore};
use subtle::{Choice, ConstantTimeEq};
/// Secret pair of `a` and `b` defining a [`SecretKey`]
///
/// ## Safety
///
/// To ensure that no secret information lingers in memory after the variable
/// goes out of scope, we advice calling `zeroize` before the variable goes out
/// of scope.
///
/// ## Examples
///
/// Generate a random `SecretKey`:
/// ```
/// use phoenix_core::SecretKey;
/// use rand::rngs::StdRng;
/// use rand::SeedableRng;
/// use zeroize::Zeroize;
///
/// let mut rng = StdRng::seed_from_u64(12345);
/// let mut sk = SecretKey::random(&mut rng);
///
/// // do something with the sk
///
/// sk.zeroize();
/// ```
///
/// # Note
/// Implementing `ZeroizeOnDrop` seems like an excellent way to lift the burden
/// of manually zeroizing after use off the user, but unfortunately it doesn't
/// delete the memory reliably. See #244
#[derive(Clone, Eq, Debug, Zeroize)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct SecretKey {
a: JubJubScalar,
b: JubJubScalar,
}
impl SecretKey {
/// This method is used to construct a new `SecretKey` from the given
/// secret pair of `a` and `b`.
pub fn new(a: JubJubScalar, b: JubJubScalar) -> Self {
Self { a, b }
}
/// Gets `a`
pub fn a(&self) -> &JubJubScalar {
&self.a
}
/// Gets `b`
pub fn b(&self) -> &JubJubScalar {
&self.b
}
/// Deterministically create a new [`SecretKey`] from a random number
/// generator
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let a = JubJubScalar::random(&mut *rng);
let b = JubJubScalar::random(&mut *rng);
SecretKey::new(a, b)
}
/// Generates a [`NoteSecretKey`] using the `R` of the given
/// [`StealthAddress`]. With the formula: `note_sk = H(a · R) + b`
pub fn gen_note_sk(&self, stealth: &StealthAddress) -> NoteSecretKey {
let aR = stealth.R() * self.a;
NoteSecretKey::from(hash(&aR) + self.b)
}
/// Checks if `note_pk ?= (H(R · a) + b) · G`
pub fn owns(&self, stealth_address: &StealthAddress) -> bool {
let note_sk = self.gen_note_sk(stealth_address);
let note_pk = GENERATOR_EXTENDED * note_sk.as_ref();
stealth_address.note_pk().as_ref() == ¬e_pk
}
}
impl ConstantTimeEq for SecretKey {
fn ct_eq(&self, other: &Self) -> Choice {
self.a.ct_eq(&other.a) & self.b.ct_eq(&other.b)
}
}
impl PartialEq for SecretKey {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl Serializable<64> for SecretKey {
type Error = Error;
fn to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&self.a.to_bytes());
bytes[32..].copy_from_slice(&self.b.to_bytes());
bytes
}
fn from_bytes(buf: &[u8; 64]) -> Result<Self, Self::Error> {
let a = JubJubScalar::from_slice(&buf[..32])?;
let b = JubJubScalar::from_slice(&buf[32..])?;
Ok(Self { a, b })
}
}