Skip to content

Commit

Permalink
refactor and document
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Apr 2, 2024
1 parent f3373a1 commit 3369703
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 30 deletions.
49 changes: 31 additions & 18 deletions src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,30 @@ use blake2b_simd::Params;
use crate::blake2b::LEAF_HASH_PREFIX;
use std::fmt;
use crate::SiaEncodable;
use ed25519_dalek::{SigningKey, Signer};
use ed25519_dalek::{SigningKey, Signer, VerifyingKey, Verifier, Signature};
use hex::{encode, decode, FromHexError};


#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct PublicKey([u8;32]);

impl PublicKey {
pub fn new(key: [u8;32]) -> Self {
PublicKey(key)
}

pub fn as_array(&self) -> [u8;32] {
self.0
}

pub fn verify_hash(&self, hash: &[u8;32], signature: &[u8;64]) -> bool {
let pk = VerifyingKey::from_bytes(&self.0).unwrap();
let sig = Signature::from_bytes(signature);
pk.verify(hash, &sig).is_ok()
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct PrivateKey([u8;64]);

impl PrivateKey {
pub fn new(key: [u8;64]) -> PrivateKey {
PrivateKey(key)
}

pub fn from_seed(seed: &[u8;32]) -> PrivateKey {
pub fn from_seed(seed: &[u8;32]) -> Self {
let sk = SigningKey::from_bytes(seed);
PrivateKey(sk.to_keypair_bytes())
}
Expand All @@ -38,7 +36,7 @@ impl PrivateKey {
}

pub fn public_key(&self) -> PublicKey {
PublicKey::new(self.0[32..].try_into().unwrap())
PublicKey(self.0[32..].try_into().unwrap())
}

pub fn sign_hash(&self, hash: &[u8;32]) -> [u8;64] {
Expand Down Expand Up @@ -66,7 +64,7 @@ impl From<FromHexError> for AddressParseError {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Address([u8;32]);

impl Address {
Expand Down Expand Up @@ -132,7 +130,7 @@ impl SiaEncodable for Address {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Algorithm {
ED25519,
}
Expand Down Expand Up @@ -172,20 +170,24 @@ impl From<FromHexError> for ParseUnlockKeyError {
}
}

#[derive(Debug, PartialEq)]
/// A public key that can be used to spend a utxo or revise a file contract
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct UnlockKey {
algorithm: Algorithm,
public_key: PublicKey,
}

impl UnlockKey {
/// Creates a new UnlockKey
pub fn new(algorithm: Algorithm, public_key: PublicKey) -> UnlockKey {
UnlockKey {
algorithm,
public_key,
}
}

/// Parses an UnlockKey from a string
/// The string should be in the format "algorithm:public_key"
pub fn parse_string(s: &str) -> Result<Self, ParseUnlockKeyError> {
let parts: Vec<&str> = s.split(':').collect();
if parts.len() != 2 {
Expand All @@ -202,7 +204,17 @@ impl UnlockKey {
return Err(ParseUnlockKeyError::InvalidLength);
}

Ok(Self::new(algorithm, PublicKey::new(key.try_into().unwrap())))
Ok(Self::new(algorithm, PublicKey(key.try_into().unwrap())))
}

// Returns the public key of the UnlockKey
pub fn public_key(&self) -> PublicKey {
self.public_key
}

/// Returns the UnlockKey as a string
pub fn as_string(&self) -> String {
format!("{}:{}", self.algorithm, encode(self.public_key.0))
}
}

Expand All @@ -216,6 +228,7 @@ impl SiaEncodable for UnlockKey {
}

// specifies the conditions for spending an output or revising a file contract.
#[derive(Debug, PartialEq)]
pub struct UnlockConditions {
pub timelock: u64,
pub public_keys: Vec<UnlockKey>,
Expand Down Expand Up @@ -328,7 +341,7 @@ mod tests {
];

for (expected, public_key) in test_cases {
let public_key = PublicKey::new(public_key.as_slice().try_into().unwrap());
let public_key = PublicKey(public_key.as_slice().try_into().unwrap());
let uc = UnlockConditions::standard_unlock_conditions(public_key);

assert_eq!(uc.address(), expected)
Expand Down
75 changes: 67 additions & 8 deletions src/currency.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::ops::{Add, Sub, Mul, Div};
use std::num::ParseIntError;
use std::str::FromStr;
use std::fmt;
Expand All @@ -22,6 +19,48 @@ impl Currency {
Currency(value)
}

pub fn parse_string(s: &str) -> Result<Self, CurrencyParseError> {
let i = s.find(|c: char| !c.is_digit(10) && c != '.').unwrap_or(s.len());
let (value, unit) = s.split_at(i);
let unit = unit.trim();

if unit.is_empty() || unit == "H" {
let value = value.parse::<u128>()?;
return Ok(Currency::new(value))
}

let scaling_factor: i32 = match unit {
"pS" => -12,
"nS" => -9,
"uS" => -6,
"mS" => -3,
"SC" => 0,
"KS" => 3,
"MS" => 6,
"GS" => 9,
"TS" => 12,
&_ => return Err(CurrencyParseError::InvalidUnit(unit.to_string())),
};

let parts: Vec<&str> = value.split('.').collect();
if parts.len() > 2 {
return Err(CurrencyParseError::InvalidFormat("too many decimal points".to_string()))
}

let integer_part = parts[0].parse::<u128>().map_err(|_| CurrencyParseError::InvalidFormat("invalid integer part".to_string()))?;
let fraction_part = if parts.len() == 2 {
parts[1].parse::<u128>().map_err(|_| CurrencyParseError::InvalidFormat("invalid integer part".to_string()))?
} else {
0
};

let frac_digits = parts.get(1).map_or(0, |frac| frac.len() as i32);
let integer = integer_part * 10u128.pow((SIACOIN_PRECISION_I32 + scaling_factor) as u32);
let fraction = fraction_part * 10u128.pow((SIACOIN_PRECISION_I32 - frac_digits + scaling_factor) as u32);

Ok(Currency::new(integer+fraction))
}

/// Converts a given amount of Siacoins into the `Currency` type.
///
/// This function takes the amount of Siacoins as a `u64` and converts it into
Expand All @@ -38,37 +77,57 @@ impl Currency {
pub fn siacoins(n: u64) -> Self {
Currency::new((n as u128) * 10u128.pow(SIACOIN_PRECISION_U32))
}

pub fn checked_add(self, other: Currency) -> Option<Self> {
let v = self.0.checked_add(other.0)?;
Some(Currency(v))
}

pub fn checked_sub(self, other: Currency) -> Option<Self> {
let v = self.0.checked_sub(other.0)?;
Some(Currency(v))
}

pub fn checked_mul(self, other: Currency) -> Option<Self> {
let v = self.0.checked_mul(other.0)?;
Some(Currency(v))
}

pub fn checked_div(self, other: Currency) -> Option<Self> {
let v = self.0.checked_div(other.0)?;
Some(Currency(v))
}
}

impl Add for Currency {
type Output = Self;

fn add(self, other: Self) -> Self {
Self(self.0.checked_add(other.0).expect("overflow in addition"))
Self(self.0 + other.0)
}
}

impl Sub for Currency {
type Output = Self;

fn sub(self, other: Self) -> Self {
Self(self.0.checked_sub(other.0).expect("underflow in subtraction"))
Self(self.0 - other.0)
}
}

impl Mul for Currency {
type Output = Self;

fn mul(self, other: Self) -> Self {
Self(self.0.checked_mul(other.0).expect("overflow in multiplication"))
Self(self.0 * other.0)
}
}

impl Div for Currency {
type Output = Self;

fn div(self, other: Self) -> Self {
Self(self.0.checked_div(other.0).expect("division by zero"))
Self(self.0 / other.0)
}
}

Expand Down
11 changes: 7 additions & 4 deletions src/seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct Seed([u8;16]);
#[derive(Debug, PartialEq)]
pub enum SeedError {
MnemonicError,
InvalidLength
}

impl From<MnemonicError> for SeedError {
Expand All @@ -22,12 +23,14 @@ impl Seed {

pub fn from_mnemonic(s: &str) -> Result<Self, SeedError> {
let m = Mnemonic::parse_in(Language::English, s)?;
if m.to_entropy().len() != 16 {
return Err(SeedError::InvalidLength);
}
Ok(Self(m.to_entropy().as_slice().try_into().unwrap()))
}

pub fn to_mnemonic(&self) -> Result<String, MnemonicError> {
let m = Mnemonic::from_entropy_in(Language::English, &self.0)?;
Ok(m.to_string())
pub fn to_mnemonic(&self) -> String {
Mnemonic::from_entropy_in(Language::English, &self.0).unwrap().to_string()
}

pub fn private_key(&self, index : u64) -> PrivateKey {
Expand Down Expand Up @@ -88,7 +91,7 @@ mod tests {

for (entropy, expected) in test_cases {
let seed = Seed::from_entropy(entropy);
assert_eq!(seed.to_mnemonic().unwrap(), expected);
assert_eq!(seed.to_mnemonic(), expected);
}
}

Expand Down

0 comments on commit 3369703

Please sign in to comment.