use crate::encoding;
use crate::keys::public::Public;
use bitvec::prelude::*;
use regex::Regex;
use std::convert::TryFrom;
use std::str::FromStr;
use crate::FeelessError;
#[derive(Debug, PartialEq, Clone)]
pub struct Address(String);
impl Address {
pub(crate) const LEN: usize = 65;
pub(crate) const PREFIX_LEN: usize = 5;
pub(crate) const ENCODED_PUBLIC_KEY_LEN: usize = 52;
pub(crate) const ENCODED_PADDED_BITS: usize = 4;
pub fn to_public(&self) -> Public {
self.extract_public_key().unwrap()
}
fn extract_public_key(&self) -> Result<Public, FeelessError> {
let public_key_part =
&self.0[Self::PREFIX_LEN..(Self::PREFIX_LEN + Self::ENCODED_PUBLIC_KEY_LEN)];
debug_assert_eq!(public_key_part.len(), Self::ENCODED_PUBLIC_KEY_LEN);
let bits = encoding::decode_nano_base_32(&public_key_part)?;
debug_assert_eq!(bits.len(), 8 * Public::LEN + Self::ENCODED_PADDED_BITS);
let bits: &BitVec<Msb0, u8> = &bits[Self::ENCODED_PADDED_BITS..].to_owned();
let public_key_bytes: Vec<u8> = bits.to_owned().into_vec();
debug_assert_eq!(public_key_bytes.len(), Public::LEN);
Public::try_from(public_key_bytes.as_slice())
}
fn validate_checksum(&self, public: &Public) -> Result<(), FeelessError> {
let idx = Self::PREFIX_LEN + Self::ENCODED_PUBLIC_KEY_LEN;
let checksum = &self.0[idx..];
if public.checksum() != checksum {
return Err(FeelessError::InvalidChecksum);
}
Ok(())
}
}
impl FromStr for Address {
type Err = FeelessError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let re = Regex::new("^nano_[13][13456789abcdefghijkmnopqrstuwxyz]{59}$")
.expect("Could not build regexp for nano address.");
if !re.is_match(s) {
return Err(FeelessError::InvalidAddress);
}
let address = Address(s.into());
let public = address.extract_public_key()?;
address.validate_checksum(&public)?;
Ok(address)
}
}
impl From<&Public> for Address {
fn from(public: &Public) -> Self {
let mut s = String::with_capacity(Self::LEN);
s.push_str("nano_");
const PKP_LEN: usize = Address::ENCODED_PADDED_BITS + 8 * Public::LEN;
const PKP_CAPACITY: usize = Address::ENCODED_PADDED_BITS + 8 * Public::LEN + 4; let mut bits: BitVec<Msb0, u8> = BitVec::with_capacity(PKP_CAPACITY);
let pad: BitVec<Msb0, u8> = bitvec![Msb0, u8; 0; Self::ENCODED_PADDED_BITS];
bits.extend_from_bitslice(&pad);
bits.extend_from_raw_slice(&public.as_bytes());
debug_assert_eq!(bits.capacity(), PKP_CAPACITY);
debug_assert_eq!(bits.len(), PKP_LEN);
let public_key_part = encoding::encode_nano_base_32(&bits);
s.push_str(&public_key_part);
let checksum = public.checksum();
s.push_str(&checksum);
debug_assert_eq!(s.len(), Self::LEN);
debug_assert_eq!(s.capacity(), Self::LEN);
Address(s)
}
}
impl std::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}