helium-crypto 0.7.0

Helium Blockchain cryptography library
Documentation
mod keyblob;
mod rsa_key;

use crate::{public_key, rsa, KeyTag, KeyType, Network, Result, Sign};
use std::path::Path;
use std::{fmt, io};

use crate::nova_tz::rsa_key::TzRsaKeyInfo;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum Error {
    #[error("Error reading {0}: {1}")]
    BadKeyPath(String, String),

    #[error("KeyBlob error")]
    KeyBlobError(#[from] keyblob::Error),

    #[error("qseecom error")]
    QseecomError(#[from] io::Error),
}

pub struct Keypair {
    pub network: Network,
    pub public_key: public_key::PublicKey,
    pub path: String,
    key: TzRsaKeyInfo,
}

impl PartialEq for Keypair {
    fn eq(&self, other: &Self) -> bool {
        self.network == other.network && self.public_key == other.public_key
    }
}

impl fmt::Debug for Keypair {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
        f.debug_struct("Keypair")
            .field("path", &self.path)
            .field("public", &self.public_key)
            .finish()
    }
}

impl Sign for Keypair {
    fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> {
        self.key.sign(msg)
    }
}

impl Keypair {
    pub fn from_key_path(network: Network, key_path: &Path) -> Result<Keypair> {
        let key = TzRsaKeyInfo::from_path(key_path)?;
        Keypair::from_rsa_key(network, key)
    }

    pub fn from_key_blob(network: Network, key_blob_data: &[u8]) -> Result<Keypair> {
        let key = TzRsaKeyInfo::from_key_blob_data(key_blob_data)?;
        Keypair::from_rsa_key(network, key)
    }

    fn from_rsa_key(network: Network, key: TzRsaKeyInfo) -> Result<Keypair> {
        let public_key = key.public_key()?;

        Ok(Keypair {
            network,
            public_key: public_key::PublicKey::for_network(network, rsa::PublicKey(public_key)),
            path: "blob".to_string(),
            key,
        })
    }

    pub fn key_tag(&self) -> KeyTag {
        KeyTag {
            network: self.network,
            key_type: KeyType::Rsa,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::Verify;
    use hex_literal::hex;

    #[test]
    fn verify() {
        // Test a msg signed and verified with a keypair generated with qseecom crypto
        const MSG: &[u8] = b"hello world";
        const PUBKEY: &str = "1trSusex3KsU6oyDmozsPFLC13G9DQ6A6ksZfLWY1A4zYPn5qP8cBD6CgTjZrAQQ1Tg3wTYyZx5mqrrGeaCf6UWNs6nH5MfAkeRYSKpEUcfMu1ZM5Jtj3BrMDFJFSyVgXtNSPtarSj61iFmCwSsNke87QUKGd5RcgFiE5VH3uCTNEkNmqwDrhkfkWieTQ2BRTSbhbPwmS4dKzNVUTjb7z5o7rU4AY67PrZqZPiV6MrS4vHshbLfBb8tKnFtYNwAUNnK2MK7heUMKhN6TZiCpEQE4zZrvgyAJpZd3XkbuQJDVAF18bc7QeAT4aeMKsbfdx6XYREamJyAnoHffqdokLu4stM7h8LPSNA8cT2VKrFxYuS";
        let public_key: crate::PublicKey = PUBKEY.parse().expect("b58 public key");
        const SIG: &[u8] =
            &hex!("460adb3380bd8856c47176c3235f020c85b2067a7180fe40f3936ad572941d5340267577ad314443c64c3dee997aa1c0488fb2fd9b76d018e59a8b38dfe321cf6030fe65faa0bf9ab59565fb78baa37d1a85c33745c9852845791f75545904720d2e240bc6dbff12332d6dd4a411fb4b58f67653514eaf4219f0a37c6961b38f9351abb235f5b953f94ea2db225ecdd7b73e4bf4323034a91ef8c9f617eca338a69e70da3d0cf3bebf408c837a8c60924202f510e633ed36b156215cf21553edffb3fcd845f1884fce971b60c4d12096eea8513dfbf3c7a3027502b66492504c89f0ca72b5fcaff38cd5455286cf9b88827aec15943e03d69e21bbfa10671397");
        assert!(public_key.verify(MSG, SIG).is_ok());
    }

    #[test]
    fn b58_roundtrip() {
        // Test a public key generated with qseecom crypto
        const B58: &str = "1trSusex3KsU6oyDmozsPFLC13G9DQ6A6ksZfLWY1A4zYPn5qP8cBD6CgTjZrAQQ1Tg3wTYyZx5mqrrGeaCf6UWNs6nH5MfAkeRYSKpEUcfMu1ZM5Jtj3BrMDFJFSyVgXtNSPtarSj61iFmCwSsNke87QUKGd5RcgFiE5VH3uCTNEkNmqwDrhkfkWieTQ2BRTSbhbPwmS4dKzNVUTjb7z5o7rU4AY67PrZqZPiV6MrS4vHshbLfBb8tKnFtYNwAUNnK2MK7heUMKhN6TZiCpEQE4zZrvgyAJpZd3XkbuQJDVAF18bc7QeAT4aeMKsbfdx6XYREamJyAnoHffqdokLu4stM7h8LPSNA8cT2VKrFxYuS";
        let decoded: crate::PublicKey = B58.parse().expect("b58 public key");
        assert_eq!(B58, decoded.to_string());
    }
}