key_utils/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3extern crate alloc;
4
5use alloc::{
6    string::{String, ToString},
7    vec::Vec,
8};
9use bs58::{decode, decode::Error as Bs58DecodeError};
10use core::{convert::TryFrom, fmt::Display, str::FromStr};
11use secp256k1::{
12    schnorr::Signature, Keypair, Message as SecpMessage, Secp256k1, SecretKey, SignOnly,
13    VerifyOnly, XOnlyPublicKey,
14};
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug)]
18pub enum Error {
19    Bs58Decode(Bs58DecodeError),
20    Secp256k1(secp256k1::Error),
21    KeyVersion(u16),
22    KeyLength,
23    Custom(String),
24}
25
26impl Display for Error {
27    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28        match self {
29            Self::Bs58Decode(error) => write!(f, "Base58 code error: {error}"),
30            Self::Secp256k1(error) => write!(f, "Secp256k1 error: {error}"),
31            Self::KeyVersion(obtained) => {
32                write!(f, "Unknown public key version. version found: {obtained}")
33            }
34            Self::KeyLength => write!(f, "Bad key length"),
35            Self::Custom(error) => write!(f, "Custom error: {error}"),
36        }
37    }
38}
39
40#[cfg(feature = "std")]
41impl std::error::Error for Error {}
42#[cfg(not(feature = "std"))]
43#[rustversion::since(1.81)]
44impl core::error::Error for Error {}
45
46impl From<Bs58DecodeError> for Error {
47    fn from(e: Bs58DecodeError) -> Self {
48        Error::Bs58Decode(e)
49    }
50}
51
52impl From<secp256k1::Error> for Error {
53    fn from(e: secp256k1::Error) -> Self {
54        Error::Secp256k1(e)
55    }
56}
57
58#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
59#[serde(into = "String", try_from = "String")]
60pub struct Secp256k1SecretKey(pub SecretKey);
61
62impl TryFrom<String> for Secp256k1SecretKey {
63    type Error = Error;
64
65    fn try_from(value: String) -> Result<Self, Self::Error> {
66        value.parse()
67    }
68}
69
70impl FromStr for Secp256k1SecretKey {
71    type Err = Error;
72
73    fn from_str(value: &str) -> Result<Self, Self::Err> {
74        let decoded = decode(value).with_check(None).into_vec()?;
75        let secret = SecretKey::from_slice(&decoded)?;
76        Ok(Secp256k1SecretKey(secret))
77    }
78}
79
80impl From<Secp256k1SecretKey> for String {
81    fn from(secret: Secp256k1SecretKey) -> Self {
82        secret.to_string()
83    }
84}
85
86impl Display for Secp256k1SecretKey {
87    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
88        let bytes = self.0.secret_bytes();
89        f.write_str(&bs58::encode(bytes).with_check().into_string())
90    }
91}
92
93#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
94#[serde(into = "String", try_from = "String")]
95pub struct Secp256k1PublicKey(pub XOnlyPublicKey);
96
97impl TryFrom<String> for Secp256k1PublicKey {
98    type Error = Error;
99
100    fn try_from(value: String) -> Result<Self, Self::Error> {
101        value.parse()
102    }
103}
104
105impl FromStr for Secp256k1PublicKey {
106    type Err = Error;
107
108    fn from_str(value: &str) -> Result<Self, Self::Err> {
109        let decoded = decode(value).with_check(None).into_vec()?;
110        if decoded.len() < 34 {
111            return Err(Error::KeyLength);
112        }
113        let key_version =
114            u16::from_le_bytes(decoded[..2].try_into().expect("Invalid array length"));
115        if key_version != 1 {
116            return Err(Error::KeyVersion(key_version));
117        }
118        let public = XOnlyPublicKey::from_slice(&decoded[2..]).map_err(Error::Secp256k1)?;
119        Ok(Secp256k1PublicKey(public))
120    }
121}
122
123impl From<Secp256k1PublicKey> for String {
124    fn from(public: Secp256k1PublicKey) -> Self {
125        public.to_string()
126    }
127}
128
129impl Display for Secp256k1PublicKey {
130    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131        let mut output = [0_u8; 34];
132        output[0] = 1;
133        let bytes = self.0.serialize();
134        output[2..].copy_from_slice(&bytes);
135        f.write_str(&bs58::encode(&output).with_check().into_string())
136    }
137}
138
139impl Secp256k1PublicKey {
140    pub fn into_bytes(self) -> [u8; 32] {
141        self.0.serialize()
142    }
143}
144impl Secp256k1SecretKey {
145    pub fn into_bytes(self) -> [u8; 32] {
146        self.0.secret_bytes()
147    }
148}
149
150impl From<Secp256k1SecretKey> for Secp256k1PublicKey {
151    fn from(value: Secp256k1SecretKey) -> Self {
152        let context = secp256k1::Secp256k1::new();
153        let (x_coordinate, _) = value.0.public_key(&context).x_only_public_key();
154        Self(x_coordinate)
155    }
156}
157
158pub struct SignatureService {
159    secp_sign: Secp256k1<SignOnly>,
160    secp_verify: Secp256k1<VerifyOnly>,
161}
162
163impl SignatureService {
164    pub fn new() -> Self {
165        SignatureService {
166            secp_sign: Secp256k1::signing_only(),
167            secp_verify: Secp256k1::verification_only(),
168        }
169    }
170
171    #[cfg(feature = "std")]
172    pub fn sign(&self, message: Vec<u8>, private_key: SecretKey) -> Signature {
173        self.sign_with_rng(message, private_key, &mut rand::thread_rng())
174    }
175
176    #[inline]
177    pub fn sign_with_rng<R: rand::Rng + rand::CryptoRng>(
178        &self,
179        message: Vec<u8>,
180        private_key: SecretKey,
181        rng: &mut R,
182    ) -> Signature {
183        let secret_key = private_key;
184        let kp = Keypair::from_secret_key(&self.secp_sign, &secret_key);
185
186        self.secp_sign.sign_schnorr_with_rng(
187            &SecpMessage::from_digest_slice(&message).unwrap(),
188            &kp,
189            rng,
190        )
191    }
192
193    pub fn verify(
194        &self,
195        message: Vec<u8>,
196        signature: secp256k1::schnorr::Signature,
197        public_key: XOnlyPublicKey,
198    ) -> Result<(), secp256k1::Error> {
199        let x_only_public_key = public_key;
200
201        // Verify signature
202        self.secp_verify.verify_schnorr(
203            &signature,
204            &secp256k1::Message::from_digest_slice(&message)?,
205            &x_only_public_key,
206        )
207    }
208}
209
210impl Default for SignatureService {
211    fn default() -> Self {
212        Self::new()
213    }
214}
215
216#[cfg(test)]
217mod test {
218    use super::*;
219
220    #[test]
221    fn key_conversions() {
222        let secret_key = "zmBEmPhqo3A92FkiLVvyCz6htc3e53ph3ZbD4ASqGaLjwnFLi";
223        let public_key = "9bDuixKmZqAJnrmP746n8zU1wyAQRrus7th9dxnkPg6RzQvCnan";
224        let bad_public_key1 = "9bDuixKmZqAJnrmP746n8zU1wyAQRrus7th9dxnkPg6RzQvCnam"; // invalid checksum (swapped char)
225        let bad_public_key2 = "2myPhc5vkPzuC5FXNK5tee79WmP7uoLh55SxezoF8iqwF3E3rnPY"; // invalid version (version 12)
226        let bad_public_key3 = "2wmHTKZkLg2QzXyEXGMBXzKP7JXDUt8yy9SA5hoQwERc92qR6c"; // invalid length (1 B missing)
227
228        let error = bad_public_key1
229            .parse::<Secp256k1PublicKey>()
230            .expect_err("Bad bud public key failed to raise error");
231        assert!(
232            matches!(error, Error::Bs58Decode(_)),
233            "expected failed checksum error, got {}",
234            error
235        );
236        let error = bad_public_key2
237            .parse::<Secp256k1PublicKey>()
238            .expect_err("Bad bud public key failed to raise error");
239        assert!(
240            matches!(error, Error::KeyVersion(_)),
241            "expected invalid key version error, got {}",
242            error
243        );
244        let error = bad_public_key3
245            .parse::<Secp256k1PublicKey>()
246            .expect_err("Bad bud public key failed to raise error");
247        assert!(
248            matches!(error, Error::KeyLength),
249            "expected invalid key length error, got {}",
250            error
251        );
252
253        let parsed_key = secret_key
254            .parse::<Secp256k1SecretKey>()
255            .expect("Invalid test key");
256
257        let calculated_public_key = Secp256k1PublicKey::from(parsed_key);
258        assert_eq!(calculated_public_key.to_string(), public_key);
259
260        let parsed_public_key = public_key
261            .parse::<Secp256k1PublicKey>()
262            .expect("Invalid test pubkey");
263        assert_eq!(calculated_public_key.0, parsed_public_key.0);
264    }
265}