1use ed25519_dalek::{
4 SecretKey, Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey,
5};
6use std::{
7 fmt::{self, Debug, Display, Formatter},
8 hash::Hash,
9 str::FromStr,
10};
11
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, PartialEq, Eq)]
15pub struct Keypair(pub(crate) SigningKey);
17
18impl Keypair {
19 pub fn random() -> Keypair {
21 let mut bytes = [0u8; 32];
22
23 getrandom::fill(&mut bytes).expect("getrandom failed");
24
25 let signing_key: SigningKey = SigningKey::from_bytes(&bytes);
26
27 Keypair(signing_key)
28 }
29
30 pub fn from_secret_key(secret_key: &SecretKey) -> Keypair {
32 Keypair(SigningKey::from_bytes(secret_key))
33 }
34
35 pub fn sign(&self, message: &[u8]) -> Signature {
37 self.0.sign(message)
38 }
39
40 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
42 self.0.verify(message, signature)
43 }
44
45 pub fn secret_key(&self) -> SecretKey {
47 self.0.to_bytes()
48 }
49
50 pub fn public_key(&self) -> PublicKey {
52 PublicKey(self.0.verifying_key())
53 }
54
55 pub fn to_z32(&self) -> String {
57 self.public_key().to_string()
58 }
59
60 pub fn to_uri_string(&self) -> String {
62 self.public_key().to_uri_string()
63 }
64}
65
66#[cfg(not(wasm_browser))]
68impl Keypair {
69 pub fn from_secret_key_file(
71 secret_file_path: &std::path::Path,
72 ) -> Result<Keypair, std::io::Error> {
73 let hex_string = std::fs::read_to_string(secret_file_path)?;
74 let hex_string = hex_string.trim();
75
76 let invalid_data_err = |e: &str| std::io::Error::new(std::io::ErrorKind::InvalidData, e);
77
78 if hex_string.len() % 2 != 0 {
79 return Err(invalid_data_err("Invalid hex string length"));
80 }
81
82 let mut secret_key_bytes_vec = vec![];
83 for i in (0..hex_string.len()).step_by(2) {
84 let byte_str = &hex_string[i..i + 2];
85 let byte = u8::from_str_radix(byte_str, 16)
86 .map_err(|_| invalid_data_err("Invalid hex string"))?;
87 secret_key_bytes_vec.push(byte);
88 }
89
90 let secret_key_bytes: [u8; 32] = secret_key_bytes_vec
91 .try_into()
92 .map_err(|_| invalid_data_err("Invalid secret key length"))?;
93
94 Ok(Keypair::from_secret_key(&secret_key_bytes))
95 }
96
97 pub fn write_secret_key_file(
101 &self,
102 secret_file_path: &std::path::Path,
103 ) -> Result<(), std::io::Error> {
104 let secret = self.secret_key();
105 let hex_string: String = secret.iter().map(|b| format!("{b:02x}")).collect();
106 std::fs::write(secret_file_path, hex_string)?;
107 #[cfg(unix)]
108 {
109 use std::os::unix::fs::PermissionsExt;
110
111 std::fs::set_permissions(secret_file_path, std::fs::Permissions::from_mode(0o600))?;
112 }
113 Ok(())
114 }
115}
116
117#[derive(Clone, Eq, PartialEq, Hash)]
121pub struct PublicKey(pub(crate) VerifyingKey);
122
123impl PublicKey {
124 pub fn to_z32(&self) -> String {
126 self.to_string()
127 }
128
129 pub fn to_uri_string(&self) -> String {
131 format!("pk:{self}")
132 }
133
134 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
136 self.0.verify(message, signature)
137 }
138
139 pub fn verifying_key(&self) -> &VerifyingKey {
141 &self.0
142 }
143
144 pub fn to_bytes(&self) -> [u8; 32] {
146 self.0.to_bytes()
147 }
148
149 pub fn as_bytes(&self) -> &[u8; 32] {
151 self.0.as_bytes()
152 }
153}
154
155impl AsRef<Keypair> for Keypair {
156 fn as_ref(&self) -> &Keypair {
157 self
158 }
159}
160
161impl AsRef<PublicKey> for PublicKey {
162 fn as_ref(&self) -> &PublicKey {
163 self
164 }
165}
166
167impl TryFrom<&[u8]> for PublicKey {
168 type Error = PublicKeyError;
169
170 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
171 let bytes_32: &[u8; 32] = bytes
172 .try_into()
173 .map_err(|_| PublicKeyError::InvalidPublicKeyLength(bytes.len()))?;
174
175 Ok(Self(
176 VerifyingKey::from_bytes(bytes_32)
177 .map_err(|_| PublicKeyError::InvalidEd25519PublicKey)?,
178 ))
179 }
180}
181
182impl TryFrom<&[u8; 32]> for PublicKey {
183 type Error = PublicKeyError;
184
185 fn try_from(public: &[u8; 32]) -> Result<Self, Self::Error> {
186 Ok(Self(
187 VerifyingKey::from_bytes(public)
188 .map_err(|_| PublicKeyError::InvalidEd25519PublicKey)?,
189 ))
190 }
191}
192
193impl From<VerifyingKey> for PublicKey {
194 fn from(verifying_key: VerifyingKey) -> Self {
195 Self(verifying_key)
196 }
197}
198
199impl FromStr for PublicKey {
200 type Err = PublicKeyError;
201
202 fn from_str(s: &str) -> Result<Self, Self::Err> {
217 let mut s = s;
218
219 if s.len() > 52 {
220 s = s.split_once(':').map(|tuple| tuple.1).unwrap_or(s);
222
223 if s.len() > 52 {
224 s = s.strip_prefix("//").unwrap_or(s);
226
227 if s.len() > 52 {
228 s = s.split_once('@').map(|tuple| tuple.1).unwrap_or(s);
230
231 if s.len() > 52 {
232 s = s.split_once(':').map(|tuple| tuple.0).unwrap_or(s);
234
235 if s.len() > 52 {
236 s = s.split_once('/').map(|tuple| tuple.0).unwrap_or(s);
238
239 if s.len() > 52 {
240 s = s.split_once('?').map(|tuple| tuple.0).unwrap_or(s);
242
243 if s.len() > 52 {
244 s = s.split_once('#').map(|tuple| tuple.0).unwrap_or(s);
246
247 if s.len() > 52 {
248 if s.ends_with('.') {
249 s = s.trim_matches('.');
251 }
252
253 s = s.rsplit_once('.').map(|tuple| tuple.1).unwrap_or(s);
254 }
255 }
256 }
257 }
258 }
259 }
260 }
261 }
262
263 let bytes = if let Some(v) = base32::decode(base32::Alphabet::Z, s) {
264 Ok(v)
265 } else {
266 Err(PublicKeyError::InvalidPublicKeyEncoding)
267 }?;
268
269 bytes.as_slice().try_into()
270 }
271}
272
273impl TryFrom<&str> for PublicKey {
274 type Error = PublicKeyError;
275
276 fn try_from(s: &str) -> Result<PublicKey, PublicKeyError> {
277 PublicKey::from_str(s)
278 }
279}
280
281impl TryFrom<String> for PublicKey {
282 type Error = PublicKeyError;
283
284 fn try_from(s: String) -> Result<PublicKey, PublicKeyError> {
285 s.as_str().try_into()
286 }
287}
288
289impl TryFrom<&String> for PublicKey {
290 type Error = PublicKeyError;
291
292 fn try_from(s: &String) -> Result<PublicKey, PublicKeyError> {
293 s.as_str().try_into()
294 }
295}
296
297impl Display for PublicKey {
298 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
299 write!(
300 f,
301 "{}",
302 base32::encode(base32::Alphabet::Z, self.0.as_bytes())
303 )
304 }
305}
306
307impl Display for Keypair {
308 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
309 write!(f, "{}", self.public_key())
310 }
311}
312
313impl Debug for Keypair {
314 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315 write!(f, "Keypair({})", self.public_key())
316 }
317}
318
319impl Debug for PublicKey {
320 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321 write!(f, "PublicKey({self})")
322 }
323}
324
325impl Serialize for PublicKey {
326 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
327 where
328 S: serde::Serializer,
329 {
330 let bytes = self.to_bytes();
331 bytes.serialize(serializer)
332 }
333}
334
335impl<'de> Deserialize<'de> for PublicKey {
336 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
337 where
338 D: serde::Deserializer<'de>,
339 {
340 let bytes: [u8; 32] = Deserialize::deserialize(deserializer)?;
341
342 (&bytes).try_into().map_err(serde::de::Error::custom)
343 }
344}
345
346#[derive(thiserror::Error, Debug, PartialEq, Eq)]
347pub enum PublicKeyError {
349 #[error("Invalid PublicKey length, expected 32 bytes but got: {0}")]
350 InvalidPublicKeyLength(usize),
352
353 #[error("Invalid Ed25519 publickey; Cannot decompress Edwards point")]
354 InvalidEd25519PublicKey,
356
357 #[error("Invalid PublicKey encoding")]
358 InvalidPublicKeyEncoding,
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365
366 #[test]
367 fn test_from_string_ref() {
368 let string = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no".to_string();
369 let expected = [
370 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
371 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
372 ];
373 let public_key: PublicKey = (&string).try_into().unwrap();
374 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
375 }
376
377 #[test]
378 fn pkarr_key_generate() {
379 let key1 = Keypair::random();
380 let key2 = Keypair::from_secret_key(&key1.secret_key());
381
382 assert_eq!(key1.public_key(), key2.public_key())
383 }
384
385 #[test]
386 fn zbase32() {
387 let key1 = Keypair::random();
388 let _z32 = key1.public_key().to_string();
389
390 let key2 = Keypair::from_secret_key(&key1.secret_key());
391
392 assert_eq!(key1.public_key(), key2.public_key())
393 }
394
395 #[test]
396 fn sign_verify() {
397 let keypair = Keypair::random();
398
399 let message = b"Hello, world!";
400 let signature = keypair.sign(message);
401
402 assert!(keypair.verify(message, &signature).is_ok());
403
404 let public_key = keypair.public_key();
405 assert!(public_key.verify(message, &signature).is_ok());
406 }
407
408 #[test]
409 fn from_string() {
410 let str = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
411 let expected = [
412 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
413 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
414 ];
415
416 let public_key: PublicKey = str.try_into().unwrap();
417 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
418 }
419
420 #[test]
421 fn to_uri() {
422 let bytes = [
423 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
424 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
425 ];
426 let expected = "pk:yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
427
428 let public_key: PublicKey = (&bytes).try_into().unwrap();
429
430 assert_eq!(public_key.to_uri_string(), expected);
431 }
432
433 #[test]
434 fn from_uri() {
435 let str = "pk:yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
436 let expected = [
437 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
438 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
439 ];
440
441 let public_key: PublicKey = str.try_into().unwrap();
442 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
443 }
444
445 #[test]
446 fn from_uri_with_path() {
447 let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no///foo/bar";
448 let expected = [
449 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
450 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
451 ];
452
453 let public_key: PublicKey = str.try_into().unwrap();
454 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
455 }
456
457 #[test]
458 fn from_uri_with_query() {
459 let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no?foo=bar";
460 let expected = [
461 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
462 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
463 ];
464
465 let public_key: PublicKey = str.try_into().unwrap();
466 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
467 }
468
469 #[test]
470 fn from_uri_with_hash() {
471 let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no#foo";
472 let expected = [
473 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
474 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
475 ];
476
477 let public_key: PublicKey = str.try_into().unwrap();
478 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
479 }
480
481 #[test]
482 fn from_uri_with_subdomain() {
483 let str = "https://foo.bar.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no#foo";
484 let expected = [
485 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
486 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
487 ];
488
489 let public_key: PublicKey = str.try_into().unwrap();
490 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
491 }
492
493 #[test]
494 fn from_uri_with_trailing_dot() {
495 let str = "https://foo.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no.";
496 let expected = [
497 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
498 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
499 ];
500
501 let public_key: PublicKey = str.try_into().unwrap();
502 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
503 }
504
505 #[test]
506 fn from_uri_with_username() {
507 let str = "https://foo@yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no#foo";
508 let expected = [
509 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
510 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
511 ];
512
513 let public_key: PublicKey = str.try_into().unwrap();
514 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
515 }
516
517 #[test]
518 fn from_uri_with_port() {
519 let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no:8888";
520 let expected = [
521 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
522 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
523 ];
524
525 let public_key: PublicKey = str.try_into().unwrap();
526 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
527 }
528
529 #[test]
530 fn from_uri_complex() {
531 let str = "https://foo@bar.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no.:8888?q=v&a=b#foo";
532 let expected = [
533 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
534 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
535 ];
536
537 let public_key: PublicKey = str.try_into().unwrap();
538 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
539 }
540
541 #[test]
542 fn serde() {
543 let str = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
544 let expected = [
545 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
546 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
547 ];
548
549 let public_key: PublicKey = str.try_into().unwrap();
550
551 let bytes = postcard::to_allocvec(&public_key).unwrap();
552
553 assert_eq!(bytes, expected)
554 }
555
556 #[test]
557 fn from_uri_multiple_pkarr() {
558 let str = "https://o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
561 let expected = [
562 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
563 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
564 ];
565
566 let public_key: PublicKey = str.try_into().unwrap();
567 assert_eq!(public_key.verifying_key().as_bytes(), &expected);
568 }
569
570 #[cfg(all(not(target_family = "wasm"), feature = "tls"))]
571 #[test]
572 fn pkcs8() {
573 let str = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
574 let public_key: PublicKey = str.try_into().unwrap();
575
576 let der = public_key.to_public_key_der();
577
578 assert_eq!(
579 der.as_bytes(),
580 [
581 48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254,
585 14, 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
586 ]
587 )
588 }
589
590 #[cfg(all(not(target_family = "wasm"), feature = "tls"))]
591 #[test]
592 fn certificate() {
593 use rustls::SignatureAlgorithm;
594
595 let keypair = Keypair::from_secret_key(&[0; 32]);
596
597 let certified_key = keypair.to_rpk_certified_key();
598
599 assert_eq!(certified_key.key.algorithm(), SignatureAlgorithm::ED25519);
600
601 assert_eq!(
602 certified_key.end_entity_cert().unwrap().as_ref(),
603 [
604 48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 59, 106, 39, 188, 206, 182, 164, 45,
605 98, 163, 168, 208, 42, 111, 13, 115, 101, 50, 21, 119, 29, 226, 67, 166, 58, 192,
606 72, 161, 139, 89, 218, 41,
607 ]
608 )
609 }
610
611 #[test]
612 fn invalid_key() {
613 let key = "c1bkg8tfsyy8wcedtmw4fwhdmm7bbzhgg3z58tf43m5ow8w9mbus";
614
615 assert_eq!(
616 PublicKey::try_from(key),
617 Err(PublicKeyError::InvalidEd25519PublicKey)
618 );
619 }
620
621 #[cfg(not(wasm_browser))]
622 mod fs_ops {
623 use std::fs::write;
624
625 use tempfile::NamedTempFile;
626
627 use crate::Keypair;
628
629 #[test]
630 fn test_write_and_read_keypair() {
631 let temp_file_path = NamedTempFile::new().unwrap().path().to_path_buf();
632
633 let generated_keypair = Keypair::random();
634
635 let write_keypair_result = generated_keypair.write_secret_key_file(&temp_file_path);
636 assert!(write_keypair_result.is_ok());
637 assert!(temp_file_path.exists());
638
639 let read_keypair_result = Keypair::from_secret_key_file(&temp_file_path);
640 assert!(read_keypair_result.is_ok());
641
642 let read_keypair = read_keypair_result.unwrap();
643 assert_eq!(generated_keypair.secret_key(), read_keypair.secret_key());
644 }
645
646 #[test]
647 fn test_read_keypair_invalid_hex() {
648 let temp_file_path = NamedTempFile::new().unwrap().path().to_path_buf();
649
650 write(&temp_file_path, "invalidhex").unwrap();
651
652 let read_keypair_result = Keypair::from_secret_key_file(&temp_file_path);
654 assert!(read_keypair_result.is_err());
655 }
656
657 #[test]
658 fn test_read_keypair_invalid_length() {
659 let temp_file_path = NamedTempFile::new().unwrap().path().to_path_buf();
660
661 write(&temp_file_path, "abcd").unwrap();
662
663 let read_keypair_result = Keypair::from_secret_key_file(&temp_file_path);
665 assert!(read_keypair_result.is_err());
666 }
667 }
668}