1use std::path::Path;
2
3use anyhow::{Context, Result};
4use rand::Rng;
5use serde::{Deserialize, Serialize};
6use tycho_crypto::ed25519;
7use tycho_types::cell::HashBytes;
8
9#[derive(Debug)]
10pub struct NodeKeys {
11 pub secret: HashBytes,
12}
13
14impl NodeKeys {
15 pub fn generate() -> Self {
16 rand::random()
17 }
18
19 pub fn load_or_create<P: AsRef<Path>>(path: P) -> Result<Self> {
23 let path = path.as_ref();
24 if path.exists() {
25 NodeKeys::from_file(path).context("failed to load node keys")
26 } else {
27 let keys = NodeKeys::generate();
28 tracing::warn!(
29 node_keys_path = %path.display(),
30 public_key = %keys.public_key(),
31 "generated new node keys",
32 );
33
34 keys.save_to_file(path)
35 .context("failed to save new node keys")?;
36 Ok(keys)
37 }
38 }
39
40 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
41 tycho_util::serde_helpers::load_json_from_file(path)
42 }
43
44 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
45 tycho_util::serde_helpers::save_json_to_file(self, path)
46 }
47
48 pub fn as_secret(&self) -> ed25519::SecretKey {
49 ed25519::SecretKey::from_bytes(self.secret.0)
50 }
51
52 pub fn public_key(&self) -> ed25519::PublicKey {
53 ed25519::PublicKey::from(&self.as_secret())
54 }
55}
56
57impl<'de> Deserialize<'de> for NodeKeys {
58 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59 where
60 D: serde::Deserializer<'de>,
61 {
62 use serde::de::Error;
63
64 #[derive(Deserialize)]
65 struct PartialKeys {
66 secret: HashBytes,
67 #[serde(default)]
68 public: Option<HashBytes>,
69 }
70
71 let partial = PartialKeys::deserialize(deserializer)?;
72
73 let secret = ed25519::SecretKey::from_bytes(partial.secret.0);
74 let public = ed25519::PublicKey::from(&secret);
75
76 if let Some(stored_public) = partial.public
77 && stored_public.as_array() != public.as_bytes()
78 {
79 return Err(Error::custom(format!(
80 "public key mismatch (stored: {stored_public}, expected: {public})",
81 )));
82 }
83
84 Ok(NodeKeys {
85 secret: partial.secret,
86 })
87 }
88}
89
90impl Serialize for NodeKeys {
91 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92 where
93 S: serde::Serializer,
94 {
95 #[derive(Serialize)]
96 struct FullKeys<'a> {
97 secret: &'a HashBytes,
98 public: &'a HashBytes,
99 }
100
101 let secret = ed25519::SecretKey::from_bytes(self.secret.0);
102 let public = ed25519::PublicKey::from(&secret);
103
104 FullKeys {
105 secret: &self.secret,
106 public: HashBytes::wrap(public.as_bytes()),
107 }
108 .serialize(serializer)
109 }
110}
111
112impl rand::distr::Distribution<NodeKeys> for rand::distr::StandardUniform {
113 #[inline]
114 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> NodeKeys {
115 NodeKeys {
116 secret: rand::distr::StandardUniform.sample(rng),
117 }
118 }
119}