btcpay 0.2.0

Rust BTCPayServer client
Documentation
use std::ops::Deref;

use bitcoin::base58;

use bitcoin::secp256k1::{
    ecdsa::SerializedSignature, Error as Secp256k1Error, Message, PublicKey, Secp256k1, SecretKey,
};

use bitcoin::hashes::ripemd160::Hash as Ripemd160Hash;
use bitcoin::hashes::sha256::Hash as Sha256Hash;
use bitcoin::hashes::Hash;

#[derive(Debug, Clone)]
pub struct Cryptography;

impl Cryptography {
    pub fn generate_keypair() -> KeyPair {
        Secp256k1::signing_only()
            .generate_keypair(&mut rand::thread_rng())
            .into()
    }

    pub fn load_keypair(secret_key: SecretKey) -> KeyPair {
        let public_key = PublicKey::from_secret_key(&Secp256k1::signing_only(), &secret_key);

        KeyPair {
            secret: secret_key,
            public: public_key,
        }
    }

    pub fn get_sin_from_key(public_key: &PublicKey) -> String {
        let version = Self::get_version_from_key(public_key);
        let checksum = Self::get_checksum_from_version(&version);

        let mut buffer = version.to_vec();
        buffer.extend_from_slice(&checksum);

        base58::encode(buffer.as_ref())
    }

    pub fn sign(
        data: &[u8],
        secret_key: &SecretKey,
    ) -> Result<SerializedSignature, Secp256k1Error> {
        let hashed = Sha256Hash::hash(data).to_byte_array();

        Ok(Secp256k1::signing_only()
            .sign_ecdsa(&Message::from_slice(&hashed)?, secret_key)
            .serialize_der())
    }

    fn get_version_from_key(public_key: &PublicKey) -> [u8; 22] {
        let sh2 = Sha256Hash::hash(&public_key.serialize()).to_byte_array();
        let rp = Ripemd160Hash::hash(&sh2).to_byte_array();

        let mut ans = [0; 22];
        ans[0] = 0x0F;
        ans[1] = 0x02;
        for i in 2..22 {
            ans[i] = rp[i - 2];
        }

        ans
    }

    fn get_checksum_from_version(version: &[u8]) -> [u8; 4] {
        let h1 = Sha256Hash::hash(version).to_byte_array();
        let h2 = Sha256Hash::hash(&h1).to_byte_array();

        let mut ans = [0; 4];
        for i in 0..4 {
            ans[i] = h2[i];
        }

        ans
    }
}

#[derive(Debug, Clone)]
pub struct KeyPair {
    secret: SecretKey,
    pub public: PublicKey,
}

impl KeyPair {
    pub fn secret(&self) -> &SecretKey {
        &self.secret
    }
}

impl From<(SecretKey, PublicKey)> for KeyPair {
    fn from(other: (SecretKey, PublicKey)) -> Self {
        KeyPair {
            secret: other.0,
            public: other.1,
        }
    }
}

impl From<SecretKey> for KeyPair {
    fn from(other: SecretKey) -> Self {
        Cryptography::load_keypair(other)
    }
}

impl Deref for KeyPair {
    type Target = PublicKey;

    fn deref(&self) -> &Self::Target {
        &self.public
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use bitcoin::hashes::hex::FromHex;

    const MY_PRIVATE_KEY: &str = "31eb31ecf1a640cd91e0a1105501f36235f8c7d51d67dcf74ccc968d74cb6b25";

    #[test]
    fn test_get_sin() {
        let key = SecretKey::from_slice(&Vec::<u8>::from_hex(MY_PRIVATE_KEY).unwrap()).unwrap();
        let keypair: KeyPair = key.into();

        let sin = Cryptography::get_sin_from_key(&keypair);
        assert_eq!(sin, "TfDnXWvj6bBhkduYiZnohg5qhtDu5VWohhw")
    }
}