cashu/nuts/nut01/
secret_key.rs

1use core::fmt;
2use core::ops::Deref;
3use core::str::FromStr;
4
5use bitcoin::hashes::sha256::Hash as Sha256Hash;
6use bitcoin::hashes::Hash;
7use bitcoin::secp256k1;
8use bitcoin::secp256k1::rand::rngs::OsRng;
9use bitcoin::secp256k1::schnorr::Signature;
10use bitcoin::secp256k1::{Keypair, Message, Scalar};
11use serde::de::Visitor;
12use serde::{Deserialize, Deserializer, Serialize};
13
14use super::{Error, PublicKey};
15use crate::SECP256K1;
16
17/// SecretKey
18#[derive(Debug, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
20pub struct SecretKey {
21    #[cfg_attr(feature = "swagger", schema(value_type = String))]
22    inner: secp256k1::SecretKey,
23}
24
25impl Deref for SecretKey {
26    type Target = secp256k1::SecretKey;
27
28    fn deref(&self) -> &Self::Target {
29        &self.inner
30    }
31}
32
33impl From<secp256k1::SecretKey> for SecretKey {
34    fn from(inner: secp256k1::SecretKey) -> Self {
35        Self { inner }
36    }
37}
38
39impl fmt::Display for SecretKey {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        write!(f, "{}", self.to_secret_hex())
42    }
43}
44
45impl SecretKey {
46    /// Parse from `bytes`
47    pub fn from_slice(slice: &[u8]) -> Result<Self, Error> {
48        Ok(Self {
49            inner: secp256k1::SecretKey::from_slice(slice)?,
50        })
51    }
52
53    /// Parse from `hex` string
54    pub fn from_hex<S>(hex: S) -> Result<Self, Error>
55    where
56        S: AsRef<str>,
57    {
58        Ok(Self {
59            inner: secp256k1::SecretKey::from_str(hex.as_ref())?,
60        })
61    }
62
63    /// Generate random secret key
64    pub fn generate() -> Self {
65        let (secret_key, _) = SECP256K1.generate_keypair(&mut OsRng);
66        Self { inner: secret_key }
67    }
68
69    /// Get secret key as `hex` string
70    pub fn to_secret_hex(&self) -> String {
71        self.inner.display_secret().to_string()
72    }
73
74    /// Get secret key as `bytes`
75    pub fn as_secret_bytes(&self) -> &[u8] {
76        self.inner.as_ref()
77    }
78
79    /// Get secret key as `bytes`
80    pub fn to_secret_bytes(&self) -> [u8; 32] {
81        self.inner.secret_bytes()
82    }
83
84    /// Schnorr Signature on Message
85    pub fn sign(&self, msg: &[u8]) -> Result<Signature, Error> {
86        let hash: Sha256Hash = Sha256Hash::hash(msg);
87        let msg = Message::from_digest_slice(hash.as_ref())?;
88        Ok(SECP256K1.sign_schnorr(&msg, &Keypair::from_secret_key(&SECP256K1, &self.inner)))
89    }
90
91    /// Get public key
92    pub fn public_key(&self) -> PublicKey {
93        self.inner.public_key(&SECP256K1).into()
94    }
95
96    /// [`SecretKey`] to [`Scalar`]
97    #[inline]
98    pub fn to_scalar(self) -> Scalar {
99        Scalar::from(self.inner)
100    }
101
102    /// [`SecretKey`] as [`Scalar`]
103    #[inline]
104    pub fn as_scalar(&self) -> Scalar {
105        Scalar::from(self.inner)
106    }
107}
108
109impl FromStr for SecretKey {
110    type Err = Error;
111
112    /// Try to parse [SecretKey] from `hex` or `bech32`
113    fn from_str(secret_key: &str) -> Result<Self, Self::Err> {
114        Self::from_hex(secret_key)
115    }
116}
117
118impl Serialize for SecretKey {
119    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
120        match serializer.is_human_readable() {
121            // For human-readable formats like JSON, serialize as hex string
122            true => serializer.serialize_str(&self.to_secret_hex()),
123            // For binary formats like CBOR, use the bytes serialization
124            false => serializer.serialize_bytes(self.as_secret_bytes()),
125        }
126    }
127}
128
129impl<'de> Deserialize<'de> for SecretKey {
130    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
131        match deserializer.is_human_readable() {
132            // For human-readable formats like JSON, deserialize from hex string
133            true => {
134                let secret_key: String = String::deserialize(deserializer)?;
135                SecretKey::from_hex(secret_key).map_err(serde::de::Error::custom)
136            }
137            // For binary formats like CBOR, use the bytes deserialization
138            false => {
139                struct SecretKeyVisitor;
140
141                impl Visitor<'_> for SecretKeyVisitor {
142                    type Value = SecretKey;
143
144                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
145                        formatter.write_str("a byte array")
146                    }
147
148                    fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
149                    where
150                        E: serde::de::Error,
151                    {
152                        SecretKey::from_slice(value).map_err(serde::de::Error::custom)
153                    }
154                }
155
156                deserializer.deserialize_bytes(SecretKeyVisitor)
157            }
158        }
159    }
160}
161
162impl Drop for SecretKey {
163    fn drop(&mut self) {
164        self.inner.non_secure_erase();
165        tracing::trace!("Secret Key dropped.");
166    }
167}