mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 07:08:05 -05:00
util/address: make Address type
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
113
src/util/address.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user