1use std::cmp::Ordering;
23use std::fmt;
24use std::fmt::{Display, Formatter};
25use std::hash::{Hash, Hasher};
26use std::str::FromStr;
27
28use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str};
29use secp256k1::schnorr::Signature;
30use secp256k1::{Keypair, Message, SecretKey, XOnlyPublicKey, SECP256K1};
31
32use crate::{Algo, Chain, InvalidPubkey, InvalidSig, SsiPub, SsiSig};
33
34#[derive(Clone, Eq, PartialEq)]
35pub struct Bip340Secret(pub(crate) SecretKey);
36
37impl Ord for Bip340Secret {
38 fn cmp(&self, other: &Self) -> Ordering { self.0.secret_bytes().cmp(&other.0.secret_bytes()) }
39}
40
41impl PartialOrd for Bip340Secret {
42 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
43}
44
45impl Hash for Bip340Secret {
46 fn hash<H: Hasher>(&self, state: &mut H) { self.0.secret_bytes().hash(state) }
47}
48
49impl DisplayBaid64 for Bip340Secret {
50 const HRI: &'static str = "bip340-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; 32] { <[u8; 32]>::from(self.clone()) }
57}
58
59impl FromBaid64Str for Bip340Secret {}
60
61impl From<Bip340Secret> for [u8; 32] {
62 fn from(ssi: Bip340Secret) -> Self { ssi.0.secret_bytes() }
63}
64
65impl From<[u8; 32]> for Bip340Secret {
66 fn from(value: [u8; 32]) -> Self {
67 Self(SecretKey::from_slice(&value).expect("invalid secret key"))
68 }
69}
70
71impl Display for Bip340Secret {
72 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) }
73}
74
75impl FromStr for Bip340Secret {
76 type Err = Baid64ParseError;
77 fn from_str(s: &str) -> Result<Self, Self::Err> { Self::from_baid64_str(s) }
78}
79
80impl Bip340Secret {
81 pub fn new(chain: Chain) -> Self {
82 use rand::thread_rng;
83 loop {
84 let sk = SecretKey::new(&mut thread_rng());
85 let (pk, _) = sk.x_only_public_key(SECP256K1);
86 let data = pk.serialize();
87 if data[30] == u8::from(Algo::Bip340) && data[31] == u8::from(chain) {
88 return Self(sk);
89 }
90 }
91 }
92
93 pub fn to_public(&self) -> SsiPub {
94 let (pk, _) = self.0.x_only_public_key(SECP256K1);
95 let data = pk.serialize();
96 SsiPub::from(data)
97 }
98
99 pub fn sign(&self, msg: [u8; 32]) -> SsiSig {
100 let msg = Message::from_digest(msg);
101 let keypair = Keypair::from_secret_key(SECP256K1, &self.0);
102 let sig = SECP256K1.sign_schnorr(&msg, &keypair);
103 SsiSig(sig.serialize())
104 }
105}
106
107impl SsiPub {
108 pub fn verify_bip360(self, msg: [u8; 32], sig: SsiSig) -> Result<(), InvalidSig> {
109 let sig = Signature::from_slice(&sig.0).map_err(|_| InvalidSig::InvalidData)?;
110 let msg = Message::from_digest(msg);
111 let pk = XOnlyPublicKey::try_from(self)?;
112 sig.verify(&msg, &pk).map_err(|_| InvalidSig::InvalidSig)
113 }
114}
115
116impl TryFrom<SsiPub> for XOnlyPublicKey {
117 type Error = InvalidPubkey;
118
119 fn try_from(ssi: SsiPub) -> Result<Self, Self::Error> {
120 Self::from_slice(&<[u8; 32]>::from(ssi)).map_err(|_| InvalidPubkey)
121 }
122}
123
124impl SsiPub {
125 pub fn from_bip340(key: XOnlyPublicKey) -> Self {
126 let bytes = key.serialize();
127 Self::from(bytes)
128 }
129}