1use core::fmt;
2use core::ops::Deref;
3use core::str::FromStr;
4
5#[cfg(feature = "rand")]
6use rand::{CryptoRng, RngCore};
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9use zeroize::Zeroize;
10
11use crate::context::ContextId;
12use crate::hash::{Hash, HashError};
13
14use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
15
16#[cfg_attr(
17 feature = "borsh",
18 derive(borsh::BorshDeserialize, borsh::BorshSerialize)
19)]
20pub struct PrivateKey(Hash);
21
22impl fmt::Debug for PrivateKey {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 f.pad("PrivateKey")
25 }
26}
27
28impl Drop for PrivateKey {
29 fn drop(&mut self) {
30 unsafe {
40 let hash_ptr = &mut self.0 as *mut Hash as *mut u8;
41 let hash_size = core::mem::size_of::<Hash>();
42 core::slice::from_raw_parts_mut(hash_ptr, hash_size).zeroize();
43 }
44 }
45}
46
47impl From<[u8; 32]> for PrivateKey {
48 fn from(id: [u8; 32]) -> Self {
49 Self(id.into())
50 }
51}
52
53impl AsRef<[u8; 32]> for PrivateKey {
54 fn as_ref(&self) -> &[u8; 32] {
55 &self.0
56 }
57}
58
59impl Deref for PrivateKey {
60 type Target = [u8; 32];
61
62 fn deref(&self) -> &Self::Target {
63 &self.0
64 }
65}
66
67impl PrivateKey {
68 #[must_use]
69 pub fn public_key(&self) -> PublicKey {
70 SigningKey::from_bytes(self)
71 .verifying_key()
72 .to_bytes()
73 .into()
74 }
75
76 #[cfg(feature = "rand")]
77 pub fn random<R: CryptoRng + RngCore>(csprng: &mut R) -> Self {
78 let mut secret = [0; 32];
79
80 csprng.fill_bytes(&mut secret);
81
82 Self::from(secret)
83 }
84
85 pub fn sign(&self, message: &[u8]) -> Result<Signature, SignatureError> {
86 SigningKey::from_bytes(self).try_sign(message)
87 }
88}
89
90#[derive(Eq, Ord, Copy, Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
91#[cfg_attr(
92 feature = "borsh",
93 derive(borsh::BorshDeserialize, borsh::BorshSerialize)
94)]
95pub struct PublicKey(Hash);
96
97impl From<[u8; 32]> for PublicKey {
98 fn from(id: [u8; 32]) -> Self {
99 Self(id.into())
100 }
101}
102
103impl AsRef<[u8; 32]> for PublicKey {
104 fn as_ref(&self) -> &[u8; 32] {
105 &self.0
106 }
107}
108
109impl AsRef<[u8]> for PublicKey {
110 fn as_ref(&self) -> &[u8] {
111 self.0.as_ref() }
113}
114
115impl Deref for PublicKey {
116 type Target = [u8; 32];
117
118 fn deref(&self) -> &Self::Target {
119 &self.0
120 }
121}
122
123impl PublicKey {
124 #[must_use]
125 pub fn as_str(&self) -> &str {
126 self.0.as_str()
127 }
128
129 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
131 VerifyingKey::from_bytes(self.as_ref())?.verify(message, signature)
132 }
133
134 pub fn verify_raw_signature(
136 &self,
137 message: &[u8],
138 signature_bytes: &[u8; 64],
139 ) -> Result<(), SignatureError> {
140 let signature = Signature::from_bytes(&signature_bytes);
141 self.verify(message, &signature)
142 }
143
144 pub fn digest(&self) -> &[u8; 32] {
146 &self.0
147 }
148}
149
150impl fmt::Display for PublicKey {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 f.pad(self.as_str())
153 }
154}
155
156impl From<PublicKey> for String {
157 fn from(id: PublicKey) -> Self {
158 id.as_str().to_owned()
159 }
160}
161
162impl From<&PublicKey> for String {
163 fn from(id: &PublicKey) -> Self {
164 id.as_str().to_owned()
165 }
166}
167
168#[derive(Clone, Copy, Debug, Error)]
169#[error(transparent)]
170pub struct InvalidPublicKey(HashError);
171
172impl FromStr for PublicKey {
173 type Err = InvalidPublicKey;
174
175 fn from_str(s: &str) -> Result<Self, Self::Err> {
176 Ok(Self(s.parse().map_err(InvalidPublicKey)?))
177 }
178}
179
180#[derive(Clone, Debug, Deserialize, Serialize)]
181#[non_exhaustive]
182pub struct Did {
183 pub id: String,
184 pub root_keys: Vec<RootKey>,
185 pub client_keys: Vec<ClientKey>,
186}
187
188impl Did {
189 #[must_use]
190 pub const fn new(id: String, root_keys: Vec<RootKey>, client_keys: Vec<ClientKey>) -> Self {
191 Self {
192 id,
193 root_keys,
194 client_keys,
195 }
196 }
197}
198
199#[derive(Clone, Debug, Deserialize, Serialize)]
200#[non_exhaustive]
201pub struct RootKey {
202 pub signing_key: String,
203 #[serde(rename = "wallet")]
204 pub wallet_type: WalletType,
205 pub wallet_address: String,
206 pub created_at: u64,
207}
208
209impl RootKey {
210 #[must_use]
211 pub const fn new(
212 signing_key: String,
213 wallet_type: WalletType,
214 wallet_address: String,
215 created_at: u64,
216 ) -> Self {
217 Self {
218 signing_key,
219 wallet_type,
220 wallet_address,
221 created_at,
222 }
223 }
224}
225
226#[derive(Clone, Debug, Deserialize, Serialize)]
227#[serde(rename_all = "camelCase")]
228#[non_exhaustive]
229pub struct ClientKey {
230 #[serde(rename = "wallet")]
231 pub wallet_type: WalletType,
232 pub signing_key: String,
233 pub created_at: u64,
234 pub context_id: Option<ContextId>,
235}
236
237impl ClientKey {
238 #[must_use]
239 pub const fn new(
240 wallet_type: WalletType,
241 signing_key: String,
242 created_at: u64,
243 context_id: Option<ContextId>,
244 ) -> Self {
245 Self {
246 wallet_type,
247 signing_key,
248 created_at,
249 context_id,
250 }
251 }
252}
253
254#[derive(Clone, Debug, Deserialize, Serialize)]
255#[serde(rename_all = "camelCase")]
256#[non_exhaustive]
257pub struct ContextUser {
258 pub user_id: String,
259 pub joined_at: u64,
260}
261
262#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
263#[serde(rename_all = "UPPERCASE")]
264#[serde(tag = "type")]
265#[non_exhaustive]
266pub enum WalletType {
267 NEAR {
268 #[serde(rename = "networkId")]
269 network_id: NearNetworkId,
270 },
271}
272
273#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
274#[serde(rename_all = "lowercase")]
275#[non_exhaustive]
276pub enum NearNetworkId {
277 Mainnet,
278 Testnet,
279 #[serde(untagged)]
280 Custom(String),
281}
282
283#[cfg(test)]
284mod tests {
285 use core::mem::ManuallyDrop;
286
287 use super::*;
288
289 #[test]
290 fn test_private_key_zeroize_on_drop() {
291 let secret_bytes: [u8; 32] = [0x42; 32];
293 let mut key = ManuallyDrop::new(PrivateKey::from(secret_bytes));
294
295 assert_eq!(key.as_ref(), &secret_bytes);
297
298 let key_ptr = &*key as *const PrivateKey as *const u8;
300 let hash_size = core::mem::size_of::<Hash>();
301
302 unsafe {
307 ManuallyDrop::drop(&mut key);
308 }
309
310 let zeroed = unsafe { core::slice::from_raw_parts(key_ptr, hash_size) };
320
321 assert!(
323 zeroed.iter().all(|&b| b == 0),
324 "Key material was not properly zeroized on drop"
325 );
326 }
327
328 #[test]
329 fn test_private_key_can_sign_before_drop() {
330 let secret_bytes: [u8; 32] = [0x42; 32];
332 let key = PrivateKey::from(secret_bytes);
333
334 let message = b"test message";
336 let signature = key.sign(message);
337 assert!(signature.is_ok());
338
339 let public_key = key.public_key();
341 assert!(!AsRef::<[u8; 32]>::as_ref(&public_key)
342 .iter()
343 .all(|&b| b == 0));
344
345 let sig = signature.unwrap();
347 assert!(public_key.verify(message, &sig).is_ok());
348 }
349}