#[macro_use]
extern crate failure;
#[macro_use]
extern crate serde_derive;
extern crate forge_did;
extern crate forge_signer;
extern crate base58;
extern crate serde;
extern crate serde_json;
use failure::Error;
use serde_json::Value;
pub type Result<T> = ::std::result::Result<T, Error>;
pub type WalletType = forge_did::create_did::DidType;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Wallet {
pub w_type: WalletType,
pub sk: Vec<u8>,
pub pk: Vec<u8>,
pub address: String,
}
impl Wallet {
pub fn create_default_wallet() -> Result<Wallet> {
Self::from_wallet_type(&WalletType::default())
}
pub fn from_wallet_type(w_type: &WalletType) -> Result<Wallet> {
let (sk, pk) = forge_signer::get_key_pair(w_type.key_type);
let address = forge_did::get_did_by_pk(&pk, &Some(w_type.to_owned()))?;
Ok(Wallet {
w_type: w_type.to_owned(),
sk,
pk,
address: forge_did::create_did::get_pure_address(&address),
})
}
pub fn from_address(addr: &str) -> Result<Wallet> {
let did_type = forge_did::create_did::DidType::from_address(addr)?;
Ok(Wallet {
address: addr.to_owned(),
w_type: did_type,
..Default::default()
})
}
pub fn from_pk(pk: &[u8], w_type: &WalletType) -> Result<Wallet> {
let address = forge_did::get_did_by_pk(pk, &Some(w_type.to_owned()))?;
Ok(Wallet {
w_type: w_type.to_owned(),
sk: Vec::new(),
pk: pk.to_owned(),
address: forge_did::create_did::get_pure_address(&address),
})
}
pub fn from_sk(sk: &[u8], w_type: &WalletType) -> Result<Wallet> {
let pk = forge_signer::get_pk_by_sk(sk, &w_type.key_type);
let mut wallet = Self::from_pk(&pk, w_type)?;
wallet.sk = sk.to_owned();
Ok(wallet)
}
pub fn to_json(&self) -> Result<Value> {
let j = serde_json::to_value(self)?;
Ok(j)
}
pub fn from_json(j: Value) -> Result<Wallet> {
let wallet: Wallet = match serde_json::from_value(j) {
Ok(w) => w,
Err(e) => bail!("wallet from json failed, err {:?}", e),
};
Ok(wallet)
}
pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<bool> {
if self.pk.is_empty() {
bail!("verify failed as pk is empty");
}
let ret = forge_signer::verify(&self.pk, message, signature, self.w_type.key_type);
Ok(ret)
}
pub fn hash(&self, message: &[u8]) -> Result<Vec<u8>> {
use forge_did::create_did::HashType;
use forge_hasher::{hash, HashLen};
match self.w_type.hash_type {
Some(HashType::Keccak) => {
hash(message, Some(forge_hasher::HashType::Keccak), None, None)
}
Some(HashType::Sha3) | None => {
hash(message, Some(forge_hasher::HashType::Sha3), None, None)
}
Some(HashType::Sha2) => hash(message, Some(forge_hasher::HashType::Sha2), None, None),
Some(HashType::Keccak384) => hash(
message,
Some(forge_hasher::HashType::Keccak),
Some(HashLen::Len384),
None,
),
Some(HashType::Sha3_384) => hash(
message,
Some(forge_hasher::HashType::Sha3),
Some(HashLen::Len384),
None,
),
Some(HashType::Keccak512) => hash(
message,
Some(forge_hasher::HashType::Keccak),
Some(HashLen::Len512),
None,
),
Some(HashType::Sha3_512) => hash(
message,
Some(forge_hasher::HashType::Sha3),
Some(HashLen::Len512),
None,
),
}
}
pub fn sign(&self, message: &[u8]) -> Result<Vec<u8>> {
if self.pk.is_empty() {
bail!("sign failed as sk is empty");
}
let ret = forge_signer::sign(&self.sk, message, self.w_type.key_type);
Ok(ret)
}
pub fn format_wallet(&mut self) -> Result<()> {
self.address = forge_did::create_did::get_pure_address(&self.address);
if !self.sk.is_empty() && !self.pk.is_empty() && !self.address.is_empty()
{
return Ok(());
}
if !self.sk.is_empty() {
let new_wallet = Self::from_sk(&self.sk, &self.w_type)?;
self.pk = new_wallet.pk;
self.address = new_wallet.address;
} else if !self.pk.is_empty() {
self.address = Self::from_pk(&self.pk, &self.w_type)?.address;
}
Ok(())
}
pub fn is_valid(wallet: &Wallet) -> bool {
if !wallet.address.is_empty() {
match forge_did::create_did::DidType::from_address(&wallet.address) {
Ok(t) => {
if t != wallet.w_type {
return false;
}
}
Err(_) => return false,
};
}
false
}
}
#[cfg(test)]
mod test {
use super::forge_did::create_did::{HashType, KeyType, RoleType};
use super::WalletType;
#[test]
fn test_wallet() {
let w_type = WalletType {
role_type: Some(RoleType::Application),
key_type: Some(KeyType::Ed25519),
hash_type: Some(HashType::Sha3),
};
let sk_str ="D67C071B6F51D2B61180B9B1AA9BE0DD0704619F0E30453AB4A592B036EDE644E4852B7091317E3622068E62A5127D1FB0D4AE2FC50213295E10652D2F0ABFC7";
let sk = get_hex_from_str(sk_str);
let wallet = super::Wallet::from_sk(&sk, &w_type).unwrap();
let expect_address = "zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr".to_owned();
assert_eq!(wallet.address, expect_address);
let w_j = wallet.to_json().unwrap();
let expect_j = super::Wallet::from_json(w_j).unwrap();
assert_eq!(wallet, expect_j);
{
let w = super::Wallet {
address: "abcd".to_owned(),
sk: vec![1, 2, 3],
..Default::default()
};
let w_j = w.to_json().unwrap();
let w_s = super::Wallet::from_json(w_j).unwrap();
assert_eq!(w, w_s);
}
let message = b"hello forge rust sdk";
let sig = wallet.sign(message).unwrap();
assert!(wallet.verify(message, &sig).unwrap());
}
fn get_hex_from_str(s: &str) -> Vec<u8> {
fn char_to_hex(ch: &char) -> u8 {
return match ch {
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
'A' => 10,
'B' => 11,
'C' => 12,
'D' => 13,
'E' => 14,
'F' => 15,
_ => unreachable!(),
};
}
let mut ret = Vec::new();
let len = s.len();
if len < 1 {
return ret;
}
let upper_s = s.to_uppercase();
let mut tmp = 0u8;
let mut count = 0;
for ch in upper_s.chars() {
if count & 0x1 != 0 {
let high = (tmp & 0xF) << 4;
tmp = high + char_to_hex(&ch);
ret.push(tmp);
} else {
tmp = char_to_hex(&ch);
}
count += 1;
}
ret
}
}