1use super::prelude::*;
19use base58::ToBase58;
20use hex_slice::HexSlice;
21use openssl::bn::BigNumContext;
22use openssl::ec::{EcGroup, EcKey, PointConversionForm};
23use openssl::hash::{hash, MessageDigest};
24use openssl::nid::Nid;
25use openssl::sha::sha256;
26use safemem::prepend;
27
28pub fn new_wallet(coin: Coin) -> Result<Wallet> {
33 let bitcoin_data = match wif_data(coin) {
34 Some(data) => data,
35 None => return Err(Error::CoinNotSupported(coin)),
36 };
37
38 let group = EcGroup::from_curve_name(Nid::SECP256K1)?;
39 let mut bn_ctx = BigNumContext::new()?;
40 let key = EcKey::generate(&group)?;
41 let pub_key =
42 key.public_key()
43 .to_bytes(&group, PointConversionForm::UNCOMPRESSED, &mut bn_ctx)?;
44 let mut priv_key = key.private_key().to_vec();
45
46 let pub_hash = sha256(&pub_key);
47 let ripe_hash = hash(MessageDigest::ripemd160(), &pub_hash[..])?;
48 let mut address = ripe_hash.to_vec();
49
50 Ok(Wallet {
51 coin: coin,
52 address: base58_check(&mut address, bitcoin_data.network_version()),
53 public_key: HexSlice::new(&pub_key).format(),
54 private_key: base58_check(&mut priv_key, &[bitcoin_data.private_key_prefix()]),
55 other: None,
56 })
57}
58
59pub fn base58_check(bytes: &mut Vec<u8>, prefix: &[u8]) -> String {
65 prepend(prefix, bytes);
66 let hash = sha256(bytes);
67 let checksum = &sha256(&hash[..])[..4];
68 bytes.extend(checksum.iter().cloned());
69 bytes.as_slice().to_base58()
70}
71
72#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
75pub struct BitcoinWifData(&'static [u8], u8, &'static str, &'static str);
76
77impl BitcoinWifData {
78 #[inline]
80 pub fn network_version(self) -> &'static [u8] { self.0 }
81
82 #[inline]
84 pub fn private_key_prefix(self) -> u8 { self.1 }
85
86 #[inline]
88 pub fn wif_start(self) -> &'static str { self.2 }
89
90 #[inline]
92 pub fn cwif_start(self) -> &'static str { self.3 }
93
94 pub fn check_wif(self, s: &str) -> bool {
96 for c in self.wif_start().chars() {
97 if s.starts_with(c) {
98 return true;
99 }
100 }
101
102 false
103 }
104
105 pub fn check_cwif(self, s: &str) -> bool {
107 for c in self.cwif_start().chars() {
108 if s.starts_with(c) {
109 return true;
110 }
111 }
112
113 false
114 }
115}
116
117#[allow(match_same_arms)]
119pub fn wif_data(coin: Coin) -> Option<BitcoinWifData> {
120 Some(match coin {
121 Coin::Bitcoin => BitcoinWifData(&[0x00], 0x80, "5", "LK"),
122 Coin::Testnet => BitcoinWifData(&[0x6f], 0xef, "9", "c"),
123 Coin::Litecoin => BitcoinWifData(&[0x30], 0xb0, "6", "T"),
124 Coin::Dogecoin => BitcoinWifData(&[0x1e], 0x9e, "6", "Q"),
125 Coin::Reddcoin => BitcoinWifData(&[0x3d], 0xbd, "7", "UV"),
126 Coin::Dash => BitcoinWifData(&[0x4c], 0xcc, "7", "X"),
127 Coin::Peercoin => BitcoinWifData(&[0x37], 0xb7, "7", "U"),
128 Coin::Namecoin => BitcoinWifData(&[0x34], 0x80, "5", "LK"),
129 Coin::Feathercoin => BitcoinWifData(&[0x0e], 0x8e, "5", "N"),
130 Coin::Blackcoin => BitcoinWifData(&[0x19], 0x99, "6", "P"),
131 Coin::NuBits => BitcoinWifData(&[0x19], 0xbf, "7", "V"),
132 Coin::Mazacoin => BitcoinWifData(&[0x32], 0xe0, "8", "a"),
133 Coin::Viacoin => BitcoinWifData(&[0x47], 0xc7, "7", "W"),
134 Coin::Rubycoin => BitcoinWifData(&[0x3c], 0xbc, "7", "U"),
135 Coin::Digitalcoin => BitcoinWifData(&[0x1e], 0x9e, "6", "Q"),
136 Coin::Cannacoin => BitcoinWifData(&[0x1c], 0x9c, "6", "Q"),
137 Coin::DigiByte => BitcoinWifData(&[0x1e], 0x9e, "6", "Q"),
138 Coin::Primecoin => BitcoinWifData(&[0x17], 0x97, "6", "P"),
139 Coin::Neoscoin => BitcoinWifData(&[0x35], 0xb1, "6", "T"),
140 Coin::Jumbucks => BitcoinWifData(&[0x2b], 0xab, "6", "S"),
141 Coin::Vertcoin => BitcoinWifData(&[0x47], 0x80, "5", "LK"),
142 Coin::MonetaryUnit => BitcoinWifData(&[0x10], 0x7e, "5", "K"),
143 Coin::CanadaeCoin => BitcoinWifData(&[0x1c], 0x9c, "6", "Q"),
144 Coin::ParkByte => BitcoinWifData(&[0x37], 0xb7, "7", "U"),
145 Coin::Pandacoin => BitcoinWifData(&[0x37], 0xb7, "7", "U"),
146 Coin::Particl => BitcoinWifData(&[0x38], 0x6c, "4", "HG"),
147 Coin::Novacoin => BitcoinWifData(&[0x08], 0x88, "5", "M"),
148 Coin::Bitcoindark => BitcoinWifData(&[0x3c], 0xbc, "7", "U"),
149 Coin::Syscoin => BitcoinWifData(&[0x00], 0x80, "5", "LK"),
150 Coin::Smileycoin => BitcoinWifData(&[0x19], 0x99, "6", "P"),
151 Coin::FujiCoin => BitcoinWifData(&[0x24], 0xa4, "6", "R"),
152 Coin::ElectronicGulden => BitcoinWifData(&[0x30], 0xb0, "6", "T"),
153 Coin::Potcoin => BitcoinWifData(&[0x37], 0xb7, "7", "U"),
154 Coin::Quarkcoin => BitcoinWifData(&[0x3a], 0xba, "7", "U"),
155 Coin::Terracoin => BitcoinWifData(&[0x00], 0x80, "5", "LK"),
156 Coin::Gridcoin => BitcoinWifData(&[0x3e], 0xbe, "7", "V"),
157 Coin::Auroracoin => BitcoinWifData(&[0x17], 0x97, "6", "T"),
158 Coin::Gulden => BitcoinWifData(&[0x26], 0xa6, "6", "R"),
159 Coin::Myriadcoin => BitcoinWifData(&[0x32], 0xb2, "6", "T"),
160 Coin::Unobtanium => BitcoinWifData(&[0x82], 0xe0, "8", "a"),
161 Coin::Stratis => BitcoinWifData(&[0x3f], 0xbf, "7", "V"),
162 Coin::MarsCoin => BitcoinWifData(&[0x32], 0xb2, "6", "T"),
163 Coin::Pesetacoin => BitcoinWifData(&[0x2f], 0xaf, "6", "ST"),
164 Coin::Pinkcoin => BitcoinWifData(&[0x03], 0x83, "RQP", "L"),
165 Coin::PiggyCoin => BitcoinWifData(&[0x76], 0xf6, "9", "d"),
166 Coin::Pivx => BitcoinWifData(&[0x1e], 0xd4, "8", "Y"),
167 Coin::BitZeny => BitcoinWifData(&[0x51], 0x80, "5", "LK"),
168 Coin::StealthCoin => BitcoinWifData(&[0x3e], 0xbe, "7", "V"),
169 Coin::Vcash => BitcoinWifData(&[0x47], 0xc7, "7", "W"),
170 Coin::NavCoin => BitcoinWifData(&[0x35], 0x96, "6", "P"),
171 Coin::Zcash => BitcoinWifData(&[0x1c, 0xb8], 0x80, "5", "LK"),
172 Coin::LBRYCredits => BitcoinWifData(&[0x55], 0x80, "5", "LK"),
173 Coin::Riecoin => BitcoinWifData(&[0x3c], 0x80, "5", "LK"),
174 Coin::BitcoinCash => BitcoinWifData(&[0x00], 0x80, "5", "LK"),
175 Coin::BitcoinGold => BitcoinWifData(&[0x26], 0x80, "5", "LK"),
176 Coin::Bitcore => BitcoinWifData(&[0x00], 0x80, "5", "LK"),
177 Coin::Ember => BitcoinWifData(&[0x5c], 0x32, "2", "8"),
178 Coin::HTMLCOIN => BitcoinWifData(&[0x29], 0xa9, "6", "S"),
179 Coin::MarteXcoin => BitcoinWifData(&[0x32], 0xb2, "6", "T"),
180 Coin::Omni => BitcoinWifData(&[0x73], 0xf3, "9", "cd"),
181 Coin::BoxyCoin => BitcoinWifData(&[0x4b], 0xcb, "7", "X"),
182 Coin::Blocknet => BitcoinWifData(&[0x1a], 0x9a, "6", "P"),
183 Coin::HOdlcoin => BitcoinWifData(&[0x28], 0xa8, "5", "LK"),
184 Coin::Axe => BitcoinWifData(&[0x4b], 0xcb, "7", "X"),
185 Coin::__Nonexhaustive => unreachable!(),
186 _ => return None,
187 })
188}
189
190#[test]
191fn gen_wallets() {
192 use coin::COINS;
193
194 println!("Generating wallets for Bitcoin variants...");
195 for &coin in COINS.iter() {
196 if wif_data(coin).is_some() {
197 let wallet = new_wallet(coin).unwrap();
198 println!("Coin: {:?} ({})", coin, coin.symbol());
199 println!("Address: {}", &wallet.address);
200 println!("Public key: {}", &wallet.public_key);
201 println!("Private key: {}", &wallet.private_key);
202 println!();
203 }
204 }
205}