1use std::{fmt, str::FromStr};
2
3use cliquenet::x25519::{InvalidKeypair, InvalidPublicKey, InvalidSecretKey};
4use rand::{Rng, SeedableRng};
5use rand_chacha::ChaCha20Rng;
6use serde::{Deserialize, Serialize};
7use tagged_base64::{TaggedBase64, Tb64Error};
8
9use crate::traits::signature_key::{PrivateSignatureKey, SignatureKey};
10
11#[derive(Clone, PartialEq, Eq, Hash)]
12pub struct Keypair(cliquenet::x25519::Keypair);
13
14#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
15#[serde(transparent)]
16pub struct PublicKey(cliquenet::x25519::PublicKey);
17
18#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[serde(transparent)]
20pub struct SecretKey(cliquenet::x25519::SecretKey);
21
22impl Keypair {
23 pub fn generate() -> Result<Self, InvalidKeypair> {
24 cliquenet::x25519::Keypair::generate().map(Self)
25 }
26
27 pub fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> Result<Self, InvalidKeypair> {
28 let mut hasher = blake3::Hasher::new();
29 hasher.update(&seed);
30 hasher.update(&index.to_be_bytes());
31 let mut rng = ChaCha20Rng::from_seed(*hasher.finalize().as_bytes());
32 let seed: [u8; 32] = rng.r#gen();
33 cliquenet::x25519::Keypair::from_seed(seed).map(Self)
34 }
35
36 pub fn derive_from<K: SignatureKey>(k: &K::PrivateKey) -> Result<Self, InvalidSecretKey> {
37 let seed = blake3::derive_key("signing key -> x25519 key", &k.to_bytes());
38 let skey = SecretKey::try_from(seed)?;
39 Ok(skey.into())
40 }
41
42 pub fn public_key(&self) -> PublicKey {
43 PublicKey(self.0.public_key())
44 }
45
46 pub fn secret_key(&self) -> SecretKey {
47 SecretKey(self.0.secret_key())
48 }
49}
50
51impl PublicKey {
52 pub fn as_bytes(&self) -> [u8; 32] {
53 self.0.as_bytes()
54 }
55
56 pub fn as_slice(&self) -> &[u8] {
57 self.0.as_slice()
58 }
59}
60
61impl SecretKey {
62 pub fn public_key(&self) -> PublicKey {
63 PublicKey(self.0.public_key())
64 }
65
66 pub fn as_bytes(&self) -> [u8; 32] {
67 self.0.as_bytes()
68 }
69
70 pub fn as_slice(&self) -> &[u8] {
71 self.0.as_slice()
72 }
73}
74
75impl From<Keypair> for cliquenet::x25519::Keypair {
76 fn from(k: Keypair) -> Self {
77 k.0
78 }
79}
80
81impl From<PublicKey> for cliquenet::x25519::PublicKey {
82 fn from(k: PublicKey) -> Self {
83 k.0
84 }
85}
86
87impl From<cliquenet::x25519::PublicKey> for PublicKey {
88 fn from(k: cliquenet::x25519::PublicKey) -> Self {
89 Self(k)
90 }
91}
92
93impl From<SecretKey> for Keypair {
94 fn from(k: SecretKey) -> Self {
95 Self(k.0.into())
96 }
97}
98
99impl From<&SecretKey> for Keypair {
100 fn from(k: &SecretKey) -> Self {
101 Self::from(k.clone())
102 }
103}
104
105impl From<SecretKey> for PublicKey {
106 fn from(k: SecretKey) -> Self {
107 k.public_key()
108 }
109}
110
111impl fmt::Debug for SecretKey {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.write_str("SecretKey")
114 }
115}
116
117impl fmt::Debug for Keypair {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.debug_struct("Keypair")
120 .field("public_key", &self.public_key())
121 .field("secret_key", &"SecretKey")
122 .finish()
123 }
124}
125
126impl fmt::Debug for PublicKey {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "{}", bs58::encode(&self.as_bytes()).into_string())
129 }
130}
131
132impl fmt::Display for PublicKey {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 let tb =
135 TaggedBase64::new(X25519_PUBLIC_KEY, &self.as_bytes()[..]).map_err(|_| fmt::Error)?;
136 write!(f, "{tb}")
137 }
138}
139
140impl TryFrom<&[u8]> for PublicKey {
141 type Error = InvalidPublicKey;
142
143 fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
144 Ok(Self(cliquenet::x25519::PublicKey::try_from(s)?))
145 }
146}
147
148impl TryFrom<&[u8]> for SecretKey {
149 type Error = InvalidSecretKey;
150
151 fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
152 Ok(Self(cliquenet::x25519::SecretKey::try_from(s)?))
153 }
154}
155
156impl TryFrom<[u8; 32]> for SecretKey {
157 type Error = InvalidSecretKey;
158
159 fn try_from(a: [u8; 32]) -> Result<Self, Self::Error> {
160 Ok(Self(cliquenet::x25519::SecretKey::try_from(a)?))
161 }
162}
163
164impl TryFrom<&str> for PublicKey {
165 type Error = InvalidPublicKey;
166
167 fn try_from(s: &str) -> Result<Self, Self::Error> {
168 Ok(Self(cliquenet::x25519::PublicKey::try_from(s)?))
169 }
170}
171
172impl TryFrom<&str> for SecretKey {
173 type Error = InvalidSecretKey;
174
175 fn try_from(s: &str) -> Result<Self, Self::Error> {
176 Ok(Self(cliquenet::x25519::SecretKey::try_from(s)?))
177 }
178}
179
180const X25519_PUBLIC_KEY: &str = "X25519_PK";
181
182impl TryFrom<TaggedBase64> for PublicKey {
183 type Error = Tb64Error;
184
185 fn try_from(tb: TaggedBase64) -> Result<Self, Self::Error> {
186 if tb.tag() != X25519_PUBLIC_KEY {
187 return Err(Tb64Error::InvalidTag);
188 }
189 Self::try_from(tb.as_ref()).map_err(|_| Tb64Error::InvalidData)
190 }
191}
192
193impl TryFrom<PublicKey> for TaggedBase64 {
194 type Error = Tb64Error;
195
196 fn try_from(k: PublicKey) -> Result<Self, Self::Error> {
197 TaggedBase64::new(X25519_PUBLIC_KEY, &k.as_bytes()[..])
198 }
199}
200
201impl FromStr for PublicKey {
202 type Err = Tb64Error;
203
204 fn from_str(s: &str) -> Result<Self, Self::Err> {
205 Self::try_from(s.parse::<TaggedBase64>()?)
206 }
207}
208
209const X25519_SECRET_KEY: &str = "X25519_SK";
210
211impl TryFrom<TaggedBase64> for SecretKey {
212 type Error = Tb64Error;
213
214 fn try_from(tb: TaggedBase64) -> Result<Self, Self::Error> {
215 if tb.tag() != X25519_SECRET_KEY {
216 return Err(Tb64Error::InvalidTag);
217 }
218 Self::try_from(tb.as_ref()).map_err(|_| Tb64Error::InvalidData)
219 }
220}
221
222impl TryFrom<SecretKey> for TaggedBase64 {
223 type Error = Tb64Error;
224
225 fn try_from(k: SecretKey) -> Result<Self, Self::Error> {
226 TaggedBase64::new(X25519_SECRET_KEY, &k.as_bytes()[..])
227 }
228}