1use std::cmp::Ordering;
23use std::fmt;
24use std::fmt::{Display, Formatter};
25use std::hash::{Hash, Hasher};
26use std::ops::Deref;
27use std::str::FromStr;
28
29use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str};
30use ec25519::{KeyPair, Noise, PublicKey, SecretKey, Seed, Signature};
31
32use crate::{Algo, Chain, InvalidPubkey, InvalidSig, SsiPub, SsiSig};
33
34#[derive(Clone, Eq, PartialEq)]
35pub struct Ed25519Secret(pub(crate) SecretKey);
36
37impl Ord for Ed25519Secret {
38 fn cmp(&self, other: &Self) -> Ordering { self.0.as_slice().cmp(other.0.as_slice()) }
39}
40
41impl PartialOrd for Ed25519Secret {
42 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
43}
44
45impl Hash for Ed25519Secret {
46 fn hash<H: Hasher>(&self, state: &mut H) { self.0.as_slice().hash(state) }
47}
48
49impl DisplayBaid64<64> for Ed25519Secret {
50 const HRI: &'static str = "ed25519-priv";
51 const CHUNKING: bool = false;
52 const PREFIX: bool = true;
53 const EMBED_CHECKSUM: bool = true;
54 const MNEMONIC: bool = false;
55
56 fn to_baid64_payload(&self) -> [u8; 64] { <[u8; 64]>::from(self.clone()) }
57}
58
59impl FromBaid64Str<64> for Ed25519Secret {}
60
61impl From<Ed25519Secret> for [u8; 64] {
62 fn from(ssi: Ed25519Secret) -> Self { *ssi.0.deref() }
63}
64
65impl From<[u8; 64]> for Ed25519Secret {
66 fn from(value: [u8; 64]) -> Self {
67 Self(SecretKey::from_slice(&value).expect("invalid secret key"))
68 }
69}
70
71impl Display for Ed25519Secret {
72 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) }
73}
74
75impl FromStr for Ed25519Secret {
76 type Err = Baid64ParseError;
77 fn from_str(s: &str) -> Result<Self, Self::Err> { Self::from_baid64_str(s) }
78}
79
80impl Ed25519Secret {
81 pub fn new(chain: Chain) -> Self {
82 loop {
83 let pair = KeyPair::from_seed(Seed::generate());
84 let pk = pair.pk;
85
86 let sig = pair.sk.sign("test", Some(Noise::generate()));
87 pk.verify("test", &sig).expect("unable to create key");
88
89 if pk[30] == u8::from(Algo::Ed25519) && pk[31] == u8::from(chain) {
90 return Self(pair.sk);
91 }
92 }
93 }
94
95 pub fn to_public(&self) -> SsiPub {
96 let pk = self.0.public_key();
97 SsiPub::from(*pk)
98 }
99
100 pub fn sign(&self, msg: [u8; 32]) -> SsiSig {
101 let sig = self.0.sign(msg, None);
102 SsiSig(*sig)
103 }
104}
105
106impl SsiPub {
107 pub fn verify_ed25519(self, msg: [u8; 32], sig: SsiSig) -> Result<(), InvalidSig> {
108 let sig = Signature::from_slice(&sig.0).map_err(|_| InvalidSig::InvalidData)?;
109 let pk = PublicKey::try_from(self)?;
110 pk.verify(msg, &sig).map_err(|err| {
111 eprintln!("{err}");
112 InvalidSig::InvalidSig
113 })
114 }
115}
116
117impl TryFrom<SsiPub> for PublicKey {
118 type Error = InvalidPubkey;
119
120 fn try_from(ssi: SsiPub) -> Result<Self, Self::Error> {
121 Self::from_slice(&<[u8; 32]>::from(ssi)).map_err(|_| InvalidPubkey)
122 }
123}
124
125impl SsiPub {
126 pub fn from_ed25519(key: PublicKey) -> Self { Self::from(*key) }
127}