btc_addgen/
lib.rs

1extern crate base58check;
2extern crate rand;
3extern crate ripemd;
4extern crate secp256k1;
5extern crate sha2;
6
7use base58check::ToBase58Check;
8use core::fmt::Display;
9use hex;
10use ripemd::Ripemd160;
11use secp256k1::{PublicKey, Secp256k1, SecretKey};
12use sha2::{Digest, Sha256};
13pub struct RunResult {
14    pub private_key: String,
15    pub public_key: String,
16    pub address: String,
17}
18
19pub enum RunError {
20    ParseError(String),
21}
22impl Display for RunError {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        match self {
25            RunError::ParseError(err) => write!(f, "Parse Error: {}", err),
26        }
27    }
28}
29
30pub struct Config {
31    pub private_key: Option<String>,
32    pub version: Option<u8>,
33}
34fn get_key_pair(config: &Config) -> Result<(SecretKey, PublicKey), String> {
35    let secp = Secp256k1::new();
36
37    if let Some(private_key) = &config.private_key {
38        let data =
39            hex::decode(&private_key).expect("Unable to decode secret key from the data given.");
40        let secret =
41            SecretKey::from_slice(&data).expect("Unable to create secret key from the data given.");
42        let public = PublicKey::from_secret_key(&secp, &secret);
43        return Ok((secret, public));
44    }
45
46    let mut rng = rand::thread_rng();
47    let (secret_key, public_key) = secp.generate_keypair(&mut rng);
48
49    Ok((secret_key, public_key))
50}
51
52pub fn run(config: Config) -> Result<RunResult, RunError> {
53    // Step 1: Generate a random private key
54    let key_pair = get_key_pair(&config);
55
56    match key_pair {
57        Ok((secret_key, public_key)) => {
58            // Step 2: Generate the public key
59            let serialized_public_key = public_key.serialize_uncompressed();
60
61            // Step 3: Perform SHA-256 hashing on the public key
62            let sha256_hash = Sha256::digest(&serialized_public_key[1..]);
63
64            // Step 4: Perform RIPEMD-160 hashing on the result of SHA-256
65            let ripemd160_hash = Ripemd160::digest(&sha256_hash);
66
67            // Step 5: Read the version code
68            let version: u8 = config.version.unwrap_or(0x00);
69
70            // Step 6:
71            //      6.1 Prepend the version
72            //      6.2 Double the SHA256 & append the checksum (first 4 digits) to the payload (version + ripemd160 hash)
73            let bitcoin_address = ripemd160_hash.to_base58check(version);
74
75            Ok(RunResult {
76                address: bitcoin_address,
77                private_key: secret_key.display_secret().to_string(),
78                public_key: hex::encode(public_key.serialize_uncompressed()),
79            })
80        }
81        Err(error) => Err(RunError::ParseError(error)),
82    }
83}