util/address: make Address type

This commit is contained in:
ghassmo
2022-01-04 01:39:47 +04:00
parent 1a85e7d93a
commit bfcd69254c
4 changed files with 134 additions and 34 deletions

View File

@@ -7,11 +7,11 @@ use pasta_curves::{
pallas,
};
use rand::RngCore;
use sha2::Digest;
use crate::{
crypto::{constants::OrchardFixedBases, util::mod_r_p},
serial::{Decodable, Encodable, ReadExt, WriteExt},
util::Address,
Error, Result,
};
@@ -24,12 +24,12 @@ pub struct Keypair {
impl Keypair {
pub fn new(secret: SecretKey) -> Self {
let public = PublicKey::from_secret(secret);
Keypair { secret, public }
Self { secret, public }
}
pub fn random(mut rng: impl RngCore) -> Self {
let secret = SecretKey::random(&mut rng);
Keypair::new(secret)
Self::new(secret)
}
}
@@ -39,7 +39,7 @@ pub struct SecretKey(pub pallas::Base);
impl SecretKey {
pub fn random(mut rng: impl RngCore) -> Self {
let x = pallas::Base::random(&mut rng);
SecretKey(x)
Self(x)
}
pub fn to_bytes(self) -> [u8; 32] {
@@ -53,12 +53,12 @@ pub struct PublicKey(pub pallas::Point);
impl PublicKey {
pub fn random(mut rng: impl RngCore) -> Self {
let p = pallas::Point::random(&mut rng);
PublicKey(p)
Self(p)
}
pub fn from_secret(s: SecretKey) -> Self {
let p = OrchardFixedBases::NullifierK.generator() * mod_r_p(s.0);
PublicKey(p)
Self(p)
}
pub fn to_bytes(self) -> [u8; 32] {
@@ -66,34 +66,12 @@ impl PublicKey {
}
}
impl std::fmt::Display for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
// sha256
let mut hasher = sha2::Sha256::new();
hasher.update(self.to_bytes());
let hash = hasher.finalize();
// ripemd160
let mut hasher = ripemd160::Ripemd160::new();
hasher.update(hash);
let mut hash = hasher.finalize().to_vec();
// add version
let mut payload = vec![0x00_u8];
// add public key hash
payload.append(&mut hash);
// hash the payload + version
let mut hasher = sha2::Sha256::new();
hasher.update(payload.clone());
let payload_hash = hasher.finalize().to_vec();
payload.append(&mut payload_hash[0..4].to_vec());
// base58 encoding
let address: String = bs58::encode(payload).into_string();
write!(f, "{}", address)
impl From<Address> for PublicKey {
fn from(address: Address) -> Self {
let mut bytes = [0u8; 32];
bytes.copy_from_slice(&address.0[1..33]);
let publickey = pallas::Point::from_bytes(&bytes).unwrap();
Self(publickey)
}
}

View File

@@ -149,6 +149,12 @@ pub enum Error {
AsyncChannelSenderError,
#[error(transparent)]
AsyncChannelReceiverError(#[from] async_channel::RecvError),
/// Address
#[error("Error converting Address to PublicKey")]
AddressToPublicKeyError,
#[error("Invalid Address")]
InvalidAddress,
}
impl From<zeromq::ZmqError> for Error {

113
src/util/address.rs Normal file
View File

@@ -0,0 +1,113 @@
use std::io;
use sha2::Digest;
use crate::{
crypto::keypair::PublicKey,
serial::{Decodable, Encodable, ReadExt, WriteExt},
Error, Result,
};
enum AddressType {
Payment = 0,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Address(pub [u8; 37]);
impl Address {
pub fn from_str(address: String) -> Result<Self> {
let bytes = bs58::decode(&address).into_vec();
if bytes.is_ok() && Self::is_valid_address(bytes.as_ref().unwrap().clone()) {
let mut bytes_arr = [0u8; 37];
bytes_arr.copy_from_slice(bytes.unwrap().as_slice());
Ok(Self(bytes_arr))
} else {
return Err(Error::InvalidAddress)
}
}
fn is_valid_address(address: Vec<u8>) -> bool {
if address.starts_with(&[AddressType::Payment as u8]) && address.len() == 37 {
// hash the version + publickey to check the checksum
let mut hasher = sha2::Sha256::new();
hasher.update(address[..33].to_vec());
let payload_hash = hasher.finalize().to_vec();
payload_hash[..4] == address[33..]
} else {
false
}
}
}
impl std::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
// base58 encoding
let address: String = bs58::encode(self.0).into_string();
write!(f, "{}", address)
}
}
impl From<PublicKey> for Address {
fn from(publickey: PublicKey) -> Self {
let mut publickey = publickey.to_bytes().to_vec();
// add version
let mut address = vec![AddressType::Payment as u8];
// add public key
address.append(&mut publickey);
// hash the version + publickey
let mut hasher = sha2::Sha256::new();
hasher.update(address.clone());
let payload_hash = hasher.finalize().to_vec();
// add the 4 first bytes from the hash as checksum
address.append(&mut payload_hash[..4].to_vec());
let mut payment_address = [0u8; 37];
payment_address.copy_from_slice(address.as_slice());
Self(payment_address)
}
}
impl Encodable for Address {
fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.0)?;
Ok(37)
}
}
impl Decodable for Address {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
let mut bytes = [0u8; 37];
d.read_slice(&mut bytes)?;
Ok(Self(bytes))
}
}
#[cfg(test)]
mod tests {
use rand::rngs::OsRng;
use super::*;
use crate::crypto::keypair::{Keypair, PublicKey};
#[test]
fn test_address() -> Result<()> {
// from/to PublicKey
let keypair = Keypair::random(&mut OsRng);
let address = Address::from(keypair.public);
assert_eq!(keypair.public, PublicKey::from(address));
// from/to string
let address_str = address.to_string();
let from_str = Address::from_str(address_str.clone())?;
assert_eq!(from_str, address);
Ok(())
}
}

View File

@@ -1,3 +1,4 @@
pub mod address;
pub mod loader;
pub mod net_name;
pub mod parse;
@@ -9,3 +10,5 @@ pub use net_name::NetworkName;
pub use parse::{assign_id, decode_base10, encode_base10, generate_id, generate_id2};
pub use path::{expand_path, join_config_path};
pub use token_list::{DrkTokenList, TokenList};
pub use address::Address;