ertosns 2 лет назад
Родитель
Сommit
b8fe8c0533
2 измененных файлов с 114 добавлено и 0 удалено
  1. 4 0
      src/sdk/src/crypto/mod.rs
  2. 110 0
      src/sdk/src/crypto/wif.rs

+ 4 - 0
src/sdk/src/crypto/mod.rs

@@ -77,6 +77,10 @@ pub mod pasta_prelude {
     };
 }
 
+/// Wallet Import Format
+pub mod wif;
+pub use wif::WIF;
+
 #[macro_export]
 macro_rules! fp_from_bs58 {
     ($ty:ident) => {

+ 110 - 0
src/sdk/src/crypto/wif.rs

@@ -0,0 +1,110 @@
+use crate::{
+    crypto::{
+        constants::{MAINNET_ADDRS_PREFIX, TESTNET_ADDRS_PREFIX},
+        SecretKey,
+    },
+    error::ContractError,
+};
+use bs58;
+use pasta_curves::group::ff::PrimeField;
+use sha256;
+use std::convert::TryInto;
+
+#[derive(Clone, Debug)]
+pub struct WIF(String);
+
+/// wallet import format https://en.bitcoin.it/wiki/Wallet_import_format
+/// encodes pallas-curve base private key to base58 string.
+impl WIF {
+    /// Get inner wrapped object
+    pub fn inner(&self) -> String {
+        self.0.clone()
+    }
+}
+
+/// convert `SecretKey` to wallet import format `WIF`
+impl From<SecretKey> for WIF {
+    /// Initialize WIF from `SecretKey`
+    fn from(secretkey: SecretKey) -> Self {
+        // address to bytes
+        let address: [u8; 32] = secretkey.inner().to_repr();
+        // address prefix
+        // TODO implement is_mainnet()  in `SecretKey`
+        // let is mainnet_prefix = secretkey.is_mainnet();
+        let is_mainnet_prefix = true;
+        let prefix: [u8; 1] =
+            if is_mainnet_prefix { MAINNET_ADDRS_PREFIX } else { TESTNET_ADDRS_PREFIX };
+        // create extended address
+        let mut extended_addrs: [u8; 33] = [0; 33];
+        let (extended_addrs_prefix, extended_addrs_main) = extended_addrs.split_at_mut(1);
+        extended_addrs_prefix.copy_from_slice(&prefix);
+        extended_addrs_main.copy_from_slice(&address);
+        // extended address checksum
+        let checksum: [u8; 4] = {
+            let first_digest: String = sha256::digest_bytes(&extended_addrs);
+            let second_digest: &[u8] = &sha256::digest(first_digest).into_bytes();
+            [second_digest[0], second_digest[1], second_digest[2], second_digest[3]]
+        };
+        let mut full_address: [u8; 37] = [0; 37];
+        let (full_address_left, full_address_right) =
+            full_address.split_at_mut(extended_addrs.len());
+        full_address_left.copy_from_slice(&extended_addrs);
+        full_address_right.copy_from_slice(&checksum);
+        WIF(bs58::encode(full_address).into_string())
+    }
+}
+
+/// convert wallet import format `WIF` to `SecretKey`
+impl From<WIF> for SecretKey {
+    fn from(wif: WIF) -> Self {
+        let full_address: Vec<u8> = bs58::decode(wif.0).into_vec().unwrap();
+        // extract prefix
+        // TODO set secret key type mainnet/testnet
+        //let prefix : [u8;1] = full_address[0..1].try_into().expect("slice with incorrect length");
+        // get address
+        let addrs: [u8; 32] = full_address[1..33].try_into().expect("slice with incorrect length");
+        // get extended address
+        let extended_addrs: [u8; 33] =
+            full_address[0..33].try_into().expect("slice with incorrect length");
+        // get checksum
+        let wif_checksum: [u8; 4] =
+            full_address[33..37].try_into().expect("slice with incorrect length");
+        // validate checksum
+        let checksum: [u8; 4] = {
+            let first_digest: String = sha256::digest_bytes(&extended_addrs);
+            let second_digest: &[u8] = &sha256::digest(first_digest).into_bytes();
+            [second_digest[0], second_digest[1], second_digest[2], second_digest[3]]
+        };
+        assert!(wif_checksum == checksum);
+        let sk: Result<SecretKey, ContractError> = SecretKey::from_bytes(addrs).into();
+        sk.unwrap()
+    }
+}
+
+/// attempt to convert WIF into `SecretKey`.
+impl TryInto<SecretKey> for String {
+    type Error = String;
+    fn try_into(self) -> Result<SecretKey, Self::Error> {
+        let full_address: Vec<u8> = bs58::decode(self).into_vec().unwrap();
+        // extract prefix
+        // TODO set secret key type mainnet/testnet
+        //let prefix : [u8;1] = full_address[0..1].try_into().expect("slice with incorrect length");
+        // get address
+        let addrs: [u8; 32] = full_address[1..33].try_into().expect("slice with incorrect length");
+        // get extended address
+        let extended_addrs: [u8; 33] =
+            full_address[0..33].try_into().expect("slice with incorrect length");
+        // get checksum
+        let wif_checksum: [u8; 4] =
+            full_address[33..37].try_into().expect("slice with incorrect length");
+        // validate checksum
+        let checksum: [u8; 4] = {
+            let first_digest: String = sha256::digest_bytes(&extended_addrs);
+            let second_digest: &[u8] = &sha256::digest(first_digest).into_bytes();
+            [second_digest[0], second_digest[1], second_digest[2], second_digest[3]]
+        };
+        assert!(wif_checksum == checksum);
+        let sk: Result<SecretKey, ContractError> = SecretKey::from_bytes(addrs).into();
+        Ok(sk.unwrap())
+    }
+}