use bech32::{self, FromBase32, ToBase32};
use ed25519_dalek::PublicKey as edDalekPublicKey;
use ed25519_dalek::SecretKey as edDalekSecretKey;
use rand::{thread_rng, Rng};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use x25519_dalek::PublicKey as xDalekPublicKey;
use crate::grin_core::global;
use crate::grin_core::ser::{self, Readable, Reader, Writeable, Writer};
use crate::grin_util::secp::key::SecretKey;
use crate::util::OnionV3Address;
use crate::Error;
use std::convert::TryFrom;
use std::fmt::{self, Display};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SlatepackAddress {
pub hrp: String,
pub pub_key: edDalekPublicKey,
}
impl SlatepackAddress {
pub fn new(pub_key: &edDalekPublicKey) -> Self {
let hrp = match global::get_chain_type() {
global::ChainTypes::Mainnet => "grin",
_ => "tgrin",
};
Self {
hrp: String::from(hrp),
pub_key: pub_key.clone(),
}
}
pub fn random() -> Self {
let bytes: [u8; 32] = thread_rng().gen();
let pub_key = edDalekPublicKey::from(&edDalekSecretKey::from_bytes(&bytes).unwrap());
SlatepackAddress::new(&pub_key)
}
pub fn encoded_len(&self) -> Result<usize, Error> {
let encoded = String::try_from(self)?;
Ok(encoded.as_bytes().len() + 1)
}
pub fn to_age_pubkey_str(&self) -> Result<String, Error> {
let x_key = xDalekPublicKey::try_from(self)?;
Ok(bech32::encode("age", x_key.as_bytes().to_base32())?.to_string())
}
}
impl Display for SlatepackAddress {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&String::try_from(self).unwrap())
}
}
impl TryFrom<&str> for SlatepackAddress {
type Error = Error;
fn try_from(encoded: &str) -> Result<Self, Self::Error> {
let (hrp, data) = bech32::decode(&encoded)?;
let bytes = Vec::<u8>::from_base32(&data)?;
let pub_key = match edDalekPublicKey::from_bytes(&bytes) {
Ok(k) => k,
Err(e) => {
return Err(Error::ED25519Key(format!("{}", e)));
}
};
Ok(SlatepackAddress { hrp, pub_key })
}
}
impl TryFrom<&SlatepackAddress> for String {
type Error = Error;
fn try_from(addr: &SlatepackAddress) -> Result<Self, Self::Error> {
let encoded = bech32::encode(&addr.hrp, addr.pub_key.to_bytes().to_base32())?;
Ok(encoded.to_string())
}
}
impl From<&SlatepackAddress> for OnionV3Address {
fn from(addr: &SlatepackAddress) -> Self {
OnionV3Address::from_bytes(addr.pub_key.to_bytes())
}
}
impl TryFrom<OnionV3Address> for SlatepackAddress {
type Error = Error;
fn try_from(addr: OnionV3Address) -> Result<SlatepackAddress, Error> {
Ok(SlatepackAddress::new(&addr.to_ed25519()?))
}
}
impl TryFrom<&SlatepackAddress> for xDalekPublicKey {
type Error = Error;
fn try_from(addr: &SlatepackAddress) -> Result<Self, Self::Error> {
let cep =
curve25519_dalek::edwards::CompressedEdwardsY::from_slice(addr.pub_key.as_bytes());
let ep = match cep.decompress() {
Some(p) => p,
None => {
return Err(Error::ED25519Key(
"Can't decompress ed25519 Edwards Point".into(),
));
}
};
let res = xDalekPublicKey::from(ep.to_montgomery().to_bytes());
Ok(res)
}
}
impl TryFrom<&SecretKey> for SlatepackAddress {
type Error = Error;
fn try_from(key: &SecretKey) -> Result<Self, Self::Error> {
let d_skey = match edDalekSecretKey::from_bytes(&key.0) {
Ok(k) => k,
Err(e) => {
return Err(Error::ED25519Key(format!(
"Can't create slatepack address from SecretKey: {}",
e
)));
}
};
let d_pub_key: edDalekPublicKey = (&d_skey).into();
Ok(Self::new(&d_pub_key))
}
}
impl Serialize for SlatepackAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(
&String::try_from(self).map_err(|err| serde::ser::Error::custom(err.to_string()))?,
)
}
}
impl<'de> Deserialize<'de> for SlatepackAddress {
fn deserialize<D>(deserializer: D) -> Result<SlatepackAddress, D::Error>
where
D: Deserializer<'de>,
{
struct SlatepackAddressVisitor;
impl<'de> serde::de::Visitor<'de> for SlatepackAddressVisitor {
type Value = SlatepackAddress;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a SlatepackAddress")
}
fn visit_str<E>(self, value: &str) -> Result<SlatepackAddress, E>
where
E: serde::de::Error,
{
let s = SlatepackAddress::try_from(value)
.map_err(|err| serde::de::Error::custom(err.to_string()))?;
Ok(s)
}
}
deserializer.deserialize_str(SlatepackAddressVisitor)
}
}
impl Writeable for SlatepackAddress {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
let encoded = match String::try_from(self) {
Ok(e) => e,
Err(e) => {
error!("Cannot parse Slatepack address: {:?}, {}", self, e);
return Err(ser::Error::CorruptedData);
}
};
let bytes = encoded.as_bytes();
if bytes.len() > 255 {
error!(
"Cannot encode Slatepackaddress: {:?}, Too Long (Max 255)",
self
);
return Err(ser::Error::CorruptedData);
}
writer.write_u8(bytes.len() as u8)?;
writer.write_fixed_bytes(&bytes)
}
}
impl Readable for SlatepackAddress {
fn read<R: Reader>(reader: &mut R) -> Result<SlatepackAddress, ser::Error> {
let len = reader.read_u8()?;
let encoded = match String::from_utf8(reader.read_fixed_bytes(len as usize)?) {
Ok(a) => a,
Err(e) => {
error!("Cannot parse Slatepack address from utf8: {}", e);
return Err(ser::Error::CorruptedData);
}
};
let parsed_addr = match SlatepackAddress::try_from(encoded.as_str()) {
Ok(a) => a,
Err(e) => {
error!("Cannot parse Slatepack address: {}, {}", encoded, e);
return Err(ser::Error::CorruptedData);
}
};
Ok(parsed_addr)
}
}
#[test]
fn slatepack_address() -> Result<(), Error> {
use rand::{thread_rng, Rng};
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let sec_key_bytes: [u8; 32] = thread_rng().gen();
let ed_sec_key = edDalekSecretKey::from_bytes(&sec_key_bytes).unwrap();
let ed_pub_key = edDalekPublicKey::from(&ed_sec_key);
let addr = SlatepackAddress::new(&ed_pub_key);
let x_pub_key = xDalekPublicKey::try_from(&addr)?;
let x_dec_secret = x25519_dalek::StaticSecret::from(sec_key_bytes);
let x_pub_key_direct = xDalekPublicKey::from(&x_dec_secret);
println!("ed sec key: {:?}", ed_sec_key);
println!("ed pub key: {:?}", ed_pub_key);
println!("x pub key from addr: {:?}", x_pub_key);
println!("x pub key direct: {:?}", x_pub_key_direct);
let encoded = String::try_from(&addr).unwrap();
println!("Encoded bech32: {}", encoded);
let parsed_addr = SlatepackAddress::try_from(encoded.as_str()).unwrap();
assert_eq!(addr, parsed_addr);
let mut slatepack = super::Slatepack::default();
let mut payload: Vec<u8> = Vec::with_capacity(243);
for _ in 0..payload.capacity() {
payload.push(rand::random());
}
slatepack.payload = payload;
let orig_sp = slatepack.clone();
slatepack.try_encrypt_payload(vec![addr.clone()])?;
slatepack.try_decrypt_payload(Some(&ed_sec_key))?;
assert_eq!(orig_sp.payload, slatepack.payload);
Ok(())
}