timegraph_identity/
signer.rs1extern crate bs58;
2extern crate multibase;
3
4use rosetta_crypto::{
5 address::Ss58AddressFormatRegistry,
6 bip32::DerivedSecretKey,
7 bip39::{Language, Mnemonic},
8};
9pub use rosetta_crypto::{Algorithm, PublicKey, SecretKey, Signature};
10use std::fmt::{Debug, Formatter};
11
12pub const SIGNING_CONTEXT: &str = "substrate";
13
14pub fn bytes_decode(str: &str) -> anyhow::Result<Vec<u8>> {
15 Ok(bs58::decode(str).into_vec()?)
16}
17pub fn bytes_encode(bs: &[u8]) -> anyhow::Result<String> {
18 Ok(bs58::encode(bs).into_string())
19}
20
21pub fn bytes_decode_lower32(str: &str) -> anyhow::Result<Vec<u8>> {
22 Ok(multibase::Base::Base32Lower.decode(str)?)
23}
24pub fn bytes_encode_lower32(bs: &[u8]) -> anyhow::Result<String> {
25 Ok(multibase::Base::Base32Lower.encode(bs))
26}
27
28pub fn generate_mnemonic() -> anyhow::Result<Mnemonic> {
29 let mut entropy = [0; 32];
30 getrandom::getrandom(&mut entropy)?;
31 let mnemonic = Mnemonic::from_entropy_in(Language::English, &entropy)?;
32 Ok(mnemonic)
33}
34
35#[derive(Clone)]
36pub struct Signer(pub SecretKey);
37
38impl Debug for Signer {
39 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40 self.address()
41 .map_err(|_| std::fmt::Error)
42 .and_then(|x| write!(f, "Signer('{}')", x))
43 }
44}
45
46impl Signer {
47 pub fn from_mnemonic(mnemonic: &Mnemonic, password: &str) -> anyhow::Result<Self> {
48 let sk = DerivedSecretKey::substrate(mnemonic, password, Algorithm::Sr25519)?
49 .secret_key()
50 .clone();
51 Ok(Signer(sk))
52 }
53
54 pub fn from_bytes(bs: &[u8]) -> anyhow::Result<Self> {
55 let sk = SecretKey::from_bytes(Algorithm::Sr25519, bs)?;
56 Ok(Self(sk))
57 }
58
59 pub fn verifier_from_bytes(bs: &[u8]) -> anyhow::Result<Verifier> {
60 let pubk = PublicKey::from_bytes(Algorithm::Sr25519, bs)?;
61 Ok(Verifier(pubk))
62 }
63
64 pub fn signature_from_bytes(bs: &[u8]) -> anyhow::Result<Signature> {
65 Signature::from_bytes(Algorithm::Sr25519, bs)
66 }
67
68 pub fn pubkey_from_bytes(bs: &[u8]) -> anyhow::Result<PublicKey> {
69 PublicKey::from_bytes(Algorithm::Sr25519, bs)
70 }
71
72 pub fn pubkey_to_address(pubk: &PublicKey) -> anyhow::Result<String> {
73 let format = Ss58AddressFormatRegistry::SubstrateAccount.into();
74 Ok(pubk.to_address(format).address().to_string())
75 }
76
77 pub fn address(&self) -> anyhow::Result<String> {
78 Self::pubkey_to_address(&self.public_key())
79 }
80
81 pub fn pubkey_from_address(address: &str) -> anyhow::Result<PublicKey> {
82 let bs = bytes_decode(address)?;
83 match bs.len() {
84 32 => PublicKey::from_bytes(Algorithm::Sr25519, &bs),
85 35 => match bs.split_first() {
86 Some((x, y)) if *x == 42 => {
87 PublicKey::from_bytes(Algorithm::Sr25519, &y[0..32])
89 }
90 _ => Err(anyhow::anyhow!("invalid public key format")),
91 },
92 _ => Err(anyhow::anyhow!("invalid public key format")),
93 }
94 }
95
96 pub fn to_bytes(&self) -> anyhow::Result<Vec<u8>> {
97 Ok(self.0.to_bytes())
98 }
99
100 pub fn new() -> anyhow::Result<Self> {
101 let mnemonic = generate_mnemonic()?;
102 Self::from_mnemonic(&mnemonic, "")
103 }
104
105 pub fn secret_key(&self) -> &SecretKey {
106 &self.0
107 }
108
109 pub fn public_key(&self) -> PublicKey {
110 self.0.public_key()
111 }
112
113 pub fn stringify(&self) -> anyhow::Result<String> {
114 bytes_encode(&self.0.to_bytes())
115 }
116
117 pub fn stringify_public_key(&self) -> anyhow::Result<String> {
118 bytes_encode(&self.0.public_key().to_bytes())
119 }
120
121 pub fn sign_msg(&self, msg: &[u8], context: &str) -> anyhow::Result<Signature> {
122 Ok(self.0.sign(msg, context))
123 }
124
125 pub fn verify_msg(
126 &self,
127 msg: &[u8],
128 context: &str,
129 signature: &Signature,
130 ) -> anyhow::Result<()> {
131 Verifier(self.public_key()).verify_msg(msg, context, signature)
132 }
133}
134
135pub struct Verifier(pub PublicKey);
136
137impl Verifier {
138 pub fn verify_msg(
139 &self,
140 msg: &[u8],
141 context: &str,
142 signature: &Signature,
143 ) -> anyhow::Result<()> {
144 if let (PublicKey::Sr25519(pubk), Signature::Sr25519(sg)) = (self.0, signature) {
145 pubk.verify_simple(context.as_bytes(), msg, sg)
146 .map_err(|e| anyhow::anyhow!("{e}"))
147 } else {
148 anyhow::bail!("unsupported public key")
149 }
150 }
151}
152
153#[test]
154fn test_address_hex() -> anyhow::Result<()> {
155 Signer::pubkey_from_address("5GYRuocV6B8WJpkJDgtiM2RTct54PquWLoP2cnEuujc343z1")?;
157 assert!(
159 Signer::pubkey_from_address("1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg").is_err()
160 );
161 Ok(())
162}
163
164#[test]
165fn test_pubkey_to_address() -> anyhow::Result<()> {
166 let signer = Signer::new()?;
167 let address = signer.address()?;
168 let bs1 = signer.public_key();
169 let bs2 = Signer::pubkey_from_address(&address)?;
170 assert_eq!(bs1, bs2);
171 Ok(())
172}