use crate::{account_format, AccountError, ComputeKey, Network, PrivateKey, ViewKey};
use snarkvm_algorithms::{EncryptionScheme, SignatureScheme};
use snarkvm_curves::AffineCurve;
use snarkvm_utilities::{
fmt,
io::{Read, Result as IoResult, Write},
ops::Deref,
str::FromStr,
FromBytes,
FromBytesDeserializer,
ToBytes,
ToBytesSerializer,
};
use bech32::{self, FromBase32, ToBase32};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[derive(Derivative)]
#[derivative(
Default(bound = "N: Network"),
Copy(bound = "N: Network"),
Clone(bound = "N: Network"),
PartialEq(bound = "N: Network"),
Eq(bound = "N: Network"),
Hash(bound = "N: Network")
)]
pub struct Address<N: Network>(<N::AccountEncryptionScheme as EncryptionScheme>::PublicKey);
impl<N: Network> Address<N> {
pub fn from_private_key(private_key: &PrivateKey<N>) -> Self {
Self::from_compute_key(&private_key.to_compute_key())
}
pub fn from_compute_key(compute_key: &ComputeKey<N>) -> Self {
Self(compute_key.to_encryption_key())
}
pub fn from_view_key(view_key: &ViewKey<N>) -> Self {
Self(N::account_encryption_scheme().generate_public_key(&*view_key))
}
pub fn verify_signature(&self, message: &[u8], signature: &N::AccountSignature) -> Result<bool, AccountError> {
Ok(N::account_signature_scheme().verify(&self.0, message, signature)?)
}
}
impl<N: Network> From<PrivateKey<N>> for Address<N> {
fn from(private_key: PrivateKey<N>) -> Self {
Self::from(&private_key)
}
}
impl<N: Network> From<&PrivateKey<N>> for Address<N> {
fn from(private_key: &PrivateKey<N>) -> Self {
Self::from_private_key(private_key)
}
}
impl<N: Network> From<ComputeKey<N>> for Address<N> {
fn from(compute_key: ComputeKey<N>) -> Self {
Self::from(&compute_key)
}
}
impl<N: Network> From<&ComputeKey<N>> for Address<N> {
fn from(compute_key: &ComputeKey<N>) -> Self {
Self::from_compute_key(compute_key)
}
}
impl<N: Network> From<ViewKey<N>> for Address<N> {
fn from(view_key: ViewKey<N>) -> Self {
Self::from(&view_key)
}
}
impl<N: Network> From<&ViewKey<N>> for Address<N> {
fn from(view_key: &ViewKey<N>) -> Self {
Self::from_view_key(view_key)
}
}
impl<N: Network> FromBytes for Address<N> {
#[inline]
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
let x_coordinate = N::ProgramBaseField::read_le(&mut reader)?;
if let Some(element) = N::ProgramAffineCurve::from_x_coordinate(x_coordinate, true) {
if element.is_in_correct_subgroup_assuming_on_curve() {
return Ok(Self(element));
}
}
if let Some(element) = N::ProgramAffineCurve::from_x_coordinate(x_coordinate, false) {
if element.is_in_correct_subgroup_assuming_on_curve() {
return Ok(Self(element));
}
}
Err(AccountError::Message("Failed to read encryption public key address".into()).into())
}
}
impl<N: Network> ToBytes for Address<N> {
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
self.0.to_x_coordinate().write_le(&mut writer)
}
}
impl<N: Network> FromStr for Address<N> {
type Err = AccountError;
fn from_str(address: &str) -> Result<Self, Self::Err> {
if address.len() != 63 {
return Err(AccountError::InvalidCharacterLength(address.len()));
}
let (hrp, data, variant) = bech32::decode(address)?;
if hrp != account_format::ADDRESS_PREFIX {
return Err(AccountError::InvalidPrefix(hrp));
}
if data.is_empty() {
return Err(AccountError::InvalidByteLength(0));
}
let buffer = Vec::from_base32(&data)?;
let address = Self::read_le(&buffer[..])?;
if variant != bech32::Variant::Bech32m {
eprintln!(
"[Warning] This Aleo address is in bech32 (deprecated) and should be encoded in bech32m as:\n{}",
address
);
}
Ok(address)
}
}
impl<N: Network> fmt::Display for Address<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let encryption_key = self.to_bytes_le().expect("Failed to write encryption key as bytes");
bech32::encode(
account_format::ADDRESS_PREFIX,
encryption_key.to_base32(),
bech32::Variant::Bech32m,
)
.expect("Failed to encode in bech32m")
.fmt(f)
}
}
impl<N: Network> fmt::Debug for Address<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Address {{ encryption_key: {:?} }}", self.0)
}
}
impl<N: Network> Serialize for Address<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match serializer.is_human_readable() {
true => serializer.collect_str(self),
false => ToBytesSerializer::serialize(self, serializer),
}
}
}
impl<'de, N: Network> Deserialize<'de> for Address<N> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match deserializer.is_human_readable() {
true => FromStr::from_str(&String::deserialize(deserializer)?).map_err(de::Error::custom),
false => FromBytesDeserializer::<Self>::deserialize(deserializer, "address", N::ADDRESS_SIZE_IN_BYTES),
}
}
}
impl<N: Network> Deref for Address<N> {
type Target = <N::AccountEncryptionScheme as EncryptionScheme>::PublicKey;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testnet2::Testnet2;
use rand::thread_rng;
#[test]
fn test_serde_json() {
let rng = &mut thread_rng();
let private_key = PrivateKey::new(rng);
let expected_address: Address<Testnet2> = private_key.into();
let expected_string = &expected_address.to_string();
let candidate_string = serde_json::to_string(&expected_address).unwrap();
assert_eq!(
expected_string,
serde_json::Value::from_str(&candidate_string)
.unwrap()
.as_str()
.unwrap()
);
assert_eq!(expected_address, Address::from_str(expected_string).unwrap());
assert_eq!(expected_address, serde_json::from_str(&candidate_string).unwrap());
}
#[test]
fn test_bincode() {
let rng = &mut thread_rng();
let private_key = PrivateKey::new(rng);
let expected_address: Address<Testnet2> = private_key.into();
let expected_bytes = expected_address.to_bytes_le().unwrap();
assert_eq!(&expected_bytes[..], &bincode::serialize(&expected_address).unwrap()[..]);
assert_eq!(expected_address, Address::read_le(&expected_bytes[..]).unwrap());
assert_eq!(expected_address, bincode::deserialize(&expected_bytes[..]).unwrap());
}
}