Skip to main content

valence_crypto_utils/
types.rs

1use core::{fmt, str::FromStr};
2
3use alloc::{
4    string::{String, ToString},
5    vec::Vec,
6};
7use k256::ecdsa::SigningKey;
8use serde::{Deserialize, Serialize};
9
10use crate::Signer;
11
12/// A [Signer] representation for environment variables.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub enum SignerEnv {
15    /// A secp256k1 signer representation.
16    SecretEccNistP256(String),
17}
18
19impl Signer {
20    /// Default environment variable name.
21    pub const ENV: &str = "VALENCE_SIGNER";
22
23    /// Attempts to create a secp256k1 signer from the provided secret.
24    pub fn from_secret(secret: &[u8]) -> anyhow::Result<Self> {
25        let secret = SigningKey::from_slice(secret)
26            .map_err(|e| anyhow::anyhow!("error parsing the secret: {e}"))?;
27
28        Ok(secret.into())
29    }
30
31    /// Returns the public identity of the signer.
32    pub fn to_public(&self) -> Vec<u8> {
33        match self {
34            Signer::SecretEccNistP256(secret) => secret.verifying_key().to_sec1_bytes().to_vec(),
35        }
36    }
37
38    /// Writes the serialized instance as environment variable into the formatter.
39    pub fn to_env(&self) -> String {
40        SignerEnv::from(self).to_string()
41    }
42}
43
44impl From<&Signer> for SignerEnv {
45    fn from(signer: &Signer) -> Self {
46        match signer {
47            Signer::SecretEccNistP256(secret) => {
48                let secret = secret.to_bytes();
49                let secret = const_hex::encode(secret);
50
51                Self::SecretEccNistP256(secret)
52            }
53        }
54    }
55}
56
57impl fmt::Display for Signer {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        use Signer::*;
60
61        match self {
62            SecretEccNistP256(secret) => {
63                let public = secret.verifying_key().to_sec1_bytes();
64                let public = const_hex::encode(public);
65
66                write!(f, "EccNistP256({public})")
67            }
68        }
69    }
70}
71
72impl fmt::Display for SignerEnv {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        let env = serde_json::to_string(&self).expect("serialization is infallible");
75
76        write!(f, "{env}")
77    }
78}
79
80impl TryFrom<SignerEnv> for Signer {
81    type Error = anyhow::Error;
82
83    fn try_from(signer: SignerEnv) -> anyhow::Result<Self> {
84        match signer {
85            SignerEnv::SecretEccNistP256(secret) => {
86                let secret = const_hex::decode(secret)?;
87
88                Signer::from_secret(&secret)
89            }
90        }
91    }
92}
93
94impl From<SigningKey> for Signer {
95    fn from(secret: SigningKey) -> Self {
96        Self::SecretEccNistP256(secret)
97    }
98}
99
100impl FromStr for Signer {
101    type Err = anyhow::Error;
102
103    fn from_str(s: &str) -> anyhow::Result<Self> {
104        SignerEnv::from_str(s).and_then(Signer::try_from)
105    }
106}
107
108impl FromStr for SignerEnv {
109    type Err = anyhow::Error;
110
111    fn from_str(s: &str) -> anyhow::Result<Self> {
112        Ok(serde_json::from_str(s)?)
113    }
114}
115
116#[cfg(feature = "std")]
117impl Signer {
118    /// Attempts to create a signer from the default environment variable [Signer::ENV].
119    pub fn try_from_env() -> anyhow::Result<Self> {
120        let env = ::std::env::var(Self::ENV)?;
121
122        Self::from_str(&env)
123    }
124}
125
126#[cfg(all(test, feature = "std"))]
127mod tests {
128    use std::env;
129
130    use super::*;
131
132    #[test]
133    fn signer_from_env_works() {
134        let secret = "b0cb16ba60d3b770eb5e001efaa8f5b94270f4e8e858f673f5e896db11d21698";
135        let secret = const_hex::decode(secret).unwrap();
136        let signer = Signer::from_secret(&secret).unwrap();
137        let public = signer.to_public();
138
139        unsafe {
140            env::set_var(Signer::ENV, signer.to_env());
141        }
142
143        let deserialized = Signer::try_from_env().unwrap().to_public();
144
145        assert_eq!(public, deserialized);
146    }
147}