1use crate::inner_types::*;
6use crate::{util::*, Token};
7use core::convert::TryFrom;
8use rand_core::*;
9use serde::{Deserialize, Serialize};
10use subtle::{Choice, ConstantTimeEq, CtOption};
11use zeroize::ZeroizeOnDrop;
12
13#[derive(Clone, Debug, Eq, Deserialize, Serialize, ZeroizeOnDrop)]
31#[zeroize(drop)]
32pub struct SecretKey {
33 pub(crate) w: Scalar,
34 pub(crate) x: Scalar,
35 pub(crate) y: Scalar,
36}
37
38impl Default for SecretKey {
39 fn default() -> Self {
40 Self {
41 w: Scalar::ZERO,
42 x: Scalar::ZERO,
43 y: Scalar::ZERO,
44 }
45 }
46}
47
48impl From<&[u8; SecretKey::BYTES]> for SecretKey {
49 fn from(data: &[u8; Self::BYTES]) -> Self {
50 Self::from_bytes(data).unwrap()
51 }
52}
53
54impl PartialEq for SecretKey {
55 fn eq(&self, other: &Self) -> bool {
56 self.ct_eq(other).unwrap_u8() == 1
57 }
58}
59
60impl ConstantTimeEq for SecretKey {
61 fn ct_eq(&self, rhs: &Self) -> Choice {
62 self.x.ct_eq(&rhs.x) & self.y.ct_eq(&rhs.y) & self.w.ct_eq(&rhs.w)
63 }
64}
65
66#[cfg(feature = "wasm")]
67wasm_slice_impl!(SecretKey);
68
69impl SecretKey {
70 pub const BYTES: usize = 96;
72
73 pub fn new(mut rng: impl RngCore + CryptoRng) -> Self {
75 Self {
76 w: Scalar::random(&mut rng),
77 x: Scalar::random(&mut rng),
78 y: Scalar::random(&mut rng),
79 }
80 }
81
82 pub fn hash(data: &[u8]) -> Self {
84 let mut values = [Scalar::ZERO; 3];
85 hash_to_scalars(&[data], &mut values);
86 Self {
87 w: values[0],
88 x: values[1],
89 y: values[2],
90 }
91 }
92
93 pub fn to_bytes(&self) -> [u8; Self::BYTES] {
95 let mut out = [0u8; Self::BYTES];
96 out[..32].copy_from_slice(&self.w.to_le_bytes()[..]);
97 out[32..64].copy_from_slice(&self.x.to_le_bytes()[..]);
98 out[64..].copy_from_slice(&self.y.to_le_bytes()[..]);
99 out
100 }
101
102 pub fn from_bytes(data: &[u8; Self::BYTES]) -> CtOption<Self> {
104 let ww = Scalar::from_le_bytes(&<[u8; 32]>::try_from(&data[..32]).unwrap());
105 let xx = Scalar::from_le_bytes(&<[u8; 32]>::try_from(&data[32..64]).unwrap());
106 let yy = Scalar::from_le_bytes(&<[u8; 32]>::try_from(&data[64..]).unwrap());
107
108 ww.and_then(|w| {
109 xx.and_then(|x| yy.and_then(|y| CtOption::new(Self { w, x, y }, Choice::from(1u8))))
110 })
111 }
112
113 pub fn sign<B: AsRef<[u8]>>(&self, id: B) -> Option<Token> {
115 Token::new(self, id)
116 }
117}