use std::collections::HashMap; use cryptoxide::hashing::blake2b_256; use minicbor::encode; use pallas_addresses::ShelleyPaymentPart; use pallas_crypto::hash::{Hash, Hasher}; use pallas_crypto::key::ed25519::Signature; use pallas_crypto::{self, key::ed25519::SecretKey}; use pallas_primitives::conway::{Tx, VKeyWitness}; use crate::tx::plutus::non_empty_set; use crate::utils::v2a; use rand::{rngs::OsRng, TryRngCore}; const PREFIX: &str = "wallet_"; pub struct Wallet { pub skey: [u8; 32], } impl Wallet { pub fn vkey(&self) -> [u8; 32] { SecretKey::from(self.skey).public_key().into() } pub fn key_hash(&self) -> Hash<28> { Hasher::<224>::hash(SecretKey::from(self.skey).public_key().as_ref()) } pub fn payment_credential(&self) -> ShelleyPaymentPart { ShelleyPaymentPart::Key(self.key_hash()) } pub fn sign_hash(&self, h: &[u8; 32]) -> Signature { SecretKey::from(self.skey).sign(h) } pub fn sign(&self, tx: &mut Tx) { let mut msg = Vec::new(); encode(&tx.transaction_body, &mut msg).unwrap(); let tx_hash = blake2b_256(&msg); let sig = self.sign_hash(&tx_hash); tx.transaction_witness_set.vkeywitness = non_empty_set(vec![VKeyWitness { vkey: self.vkey().to_vec().into(), signature: sig.as_ref().to_vec().into(), }]) } } pub fn from_env(env: &HashMap) -> Wallet { let wallet_env: HashMap = env .iter() .filter_map(|(k, v)| k.strip_prefix(PREFIX).map(|k| (k.to_string(), v.clone()))) .collect(); let raw = wallet_env.get("key").expect("wallet key not found"); let skey = parse_raw_skey(raw); Wallet { skey } } pub fn generate() -> [u8; 32] { let mut key = [0u8; 32]; OsRng.try_fill_bytes(&mut key).unwrap(); key } fn parse_raw_skey(raw: &str) -> [u8; 32] { // FIXME :: Not tested if raw.len() == 64 { // Assume hex v2a(hex::decode(raw).expect("expected hex")).expect("wrong length") } else if raw.len() == 70 { // Assume Bech v2a(bech32::decode(raw).unwrap().1).expect("wrong length") } else { panic!("Not supported") } }