rustywallet_export/
wif.rs

1//! WIF export functions.
2
3use crate::types::Network;
4use rustywallet_keys::prelude::PrivateKey;
5use rustywallet_keys::prelude::Network as KeysNetwork;
6use sha2::{Sha256, Digest};
7
8/// Export a private key to WIF format.
9///
10/// # Example
11///
12/// ```rust
13/// use rustywallet_export::{export_wif, Network};
14/// use rustywallet_keys::prelude::PrivateKey;
15///
16/// let key = PrivateKey::random();
17///
18/// // Compressed mainnet WIF (starts with K or L)
19/// let wif = export_wif(&key, Network::Mainnet, true);
20/// assert!(wif.starts_with('K') || wif.starts_with('L'));
21///
22/// // Uncompressed mainnet WIF (starts with 5)
23/// let wif = export_wif(&key, Network::Mainnet, false);
24/// assert!(wif.starts_with('5'));
25/// ```
26pub fn export_wif(key: &PrivateKey, network: Network, compressed: bool) -> String {
27    let keys_network = match network {
28        Network::Mainnet => KeysNetwork::Mainnet,
29        Network::Testnet => KeysNetwork::Testnet,
30    };
31    
32    if compressed {
33        key.to_wif(keys_network)
34    } else {
35        // Manual WIF encoding for uncompressed
36        encode_wif_uncompressed(&key.to_bytes(), keys_network)
37    }
38}
39
40/// Encode WIF for uncompressed key.
41fn encode_wif_uncompressed(key: &[u8; 32], network: KeysNetwork) -> String {
42    let version = match network {
43        KeysNetwork::Mainnet => 0x80,
44        KeysNetwork::Testnet => 0xEF,
45    };
46    
47    // Build payload: version + key (no compression flag)
48    let mut payload = Vec::with_capacity(37);
49    payload.push(version);
50    payload.extend_from_slice(key);
51    
52    // Add checksum
53    let hash1 = Sha256::digest(&payload);
54    let hash2 = Sha256::digest(hash1);
55    payload.extend_from_slice(&hash2[0..4]);
56    
57    bs58::encode(payload).into_string()
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    
64    #[test]
65    fn test_export_wif_compressed_mainnet() {
66        let key = PrivateKey::random();
67        let wif = export_wif(&key, Network::Mainnet, true);
68        assert!(wif.starts_with('K') || wif.starts_with('L'));
69        assert_eq!(wif.len(), 52);
70    }
71    
72    #[test]
73    fn test_export_wif_uncompressed_mainnet() {
74        let key = PrivateKey::random();
75        let wif = export_wif(&key, Network::Mainnet, false);
76        assert!(wif.starts_with('5'));
77        assert_eq!(wif.len(), 51);
78    }
79    
80    #[test]
81    fn test_export_wif_compressed_testnet() {
82        let key = PrivateKey::random();
83        let wif = export_wif(&key, Network::Testnet, true);
84        assert!(wif.starts_with('c'));
85    }
86    
87    #[test]
88    fn test_export_wif_uncompressed_testnet() {
89        let key = PrivateKey::random();
90        let wif = export_wif(&key, Network::Testnet, false);
91        assert!(wif.starts_with('9'));
92    }
93}