1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#![allow(non_snake_case, non_camel_case_types, deprecated, unused_assignments)]
use xdr_codec;

use std::convert::TryFrom;
use std::str::FromStr;

use crc16::{State, XMODEM};
use data_encoding;
extern crate byteorder;
use byteorder::ByteOrder;

#[allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/Stellar.rs"));

impl TryFrom<&[u8]> for uint256 {
    type Error = ();

    fn try_from(src: &[u8]) -> Result<Self, ()> {
        if src.len() != 32 {
            return Err(());
        }

        let mut output = [0u8; 32];
        for (i, val) in src.iter().enumerate() {
            output[i] = *val;
        }

        Ok(uint256(output))
    }
}

#[derive(Debug, PartialEq)]
pub enum StellarKey {
    PublicKey(uint256),
    SecretKey(uint256),
    PreAuthTx(uint256),
    Sha256Hash(uint256),
}

#[derive(Debug, PartialEq)]
pub enum StellarKeyParseError {
    Base64DecodeError,
    ChecksumError,
    KeyLengthError,
    UnknownKeyTypeError,
}

impl FromStr for StellarKey {
    type Err = StellarKeyParseError;

    fn from_str(s: &str) -> Result<StellarKey, Self::Err> {
        let decoded = match data_encoding::BASE32.decode(s.as_bytes()) {
            Ok(d) => d,
            Err(_) => return Err(StellarKeyParseError::Base64DecodeError),
        };

        let decoded_length = decoded.len();
        let version_byte = &decoded[0];
        let payload = &decoded[0..decoded_length - 2];
        let data = &payload[1..];
        let checksum = byteorder::LittleEndian::read_u16(&decoded[decoded_length - 2..]);

        let calculated_checksum = State::<XMODEM>::calculate(payload);

        if checksum != calculated_checksum {
            return Err(StellarKeyParseError::ChecksumError);
        }

        let key = match uint256::try_from(data) {
            Ok(k) => k,
            Err(_) => return Err(StellarKeyParseError::KeyLengthError),
        };

        match version_byte {
            48u8 => Ok(StellarKey::PublicKey(key)),
            144u8 => Ok(StellarKey::SecretKey(key)),
            152u8 => Ok(StellarKey::PreAuthTx(key)),
            184u8 => Ok(StellarKey::Sha256Hash(key)),
            _ => Err(StellarKeyParseError::UnknownKeyTypeError),
        }
    }
}

impl FromStr for PublicKey {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, ()> {
        match StellarKey::from_str(s) {
            Ok(StellarKey::PublicKey(key)) => Ok(PublicKey::PUBLIC_KEY_TYPE_ED25519(key)),
            _ => Err(()),
        }
    }
}

impl FromStr for SignerKey {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, ()> {
        match StellarKey::from_str(s) {
            Ok(StellarKey::SecretKey(key)) => Ok(SignerKey::SIGNER_KEY_TYPE_ED25519(key)),
            _ => Err(()),
        }
    }
}