用Rust實現區塊鏈 – 5 錢包

上一篇我們實現瞭交易,在這一部分我們通過非對稱加密算法生成密鑰對、對交易進行簽名、驗簽等操作。

錢包

包含公鑰和私鑰兩個字段

#[derive(Serialize, Deserialize, Clone)]pub struct Wallet {    pkcs8: Vec,    public_key: Vec,}
  • pkcs8:私鑰

  • public_key:公鑰

impl Wallet {    pub fn new() -> Self {        let pkcs8 = new_private_key();        let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8.as_ref()).unwrap();        let public_key = key_pair.public_key().as_ref().to_vec();        Self { pkcs8, public_key }    }    ......}

密鑰對

pub fn new_private_key() -> Vec {    let rng = SystemRandom::new();    let pkcs8 = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, &rng).unwrap();    pkcs8.as_ref().to_vec()}

使用橢圓曲線來產生私鑰,通過私鑰產生密鑰對,然後通過密鑰對導出公鑰。

地址

生成地址

pub fn get_address(&self) -> String {    let pub_key_hash = hash_pub_key(self.public_key.as_slice());    let mut payload = vec![];    payload.push(VERSION);    payload.extend(pub_key_hash.as_slice());    let checksum = checksum(payload.as_slice());    payload.extend(checksum.as_slice());    base58_encode(payload.as_slice())}pub fn hash_pub_key(pub_key: &[u8]) -> Vec {    let pub_key_sha256 = sha256_digest(pub_key);    let pub_key_ripemd160 = ripemd160_digest(&pub_key_sha256);    pub_key_ripemd160}pub fn checksum(payload: &[u8]) -> Vec {    let first_sha = sha256_digest(payload);    let second_sha = sha256_digest(&first_sha);    second_sha[0..ADDRESS_CHECKSUM_LEN].to_vec()}
  • 先使用SHA256對公鑰進行一次哈希,對結果使用RIPEMD160進行二次哈希。

  • 給哈希值加上版本前綴,這裡硬編碼為 const VERSION: u8 = 0x00。

  • 對上一步生成的結果,使用 SHA256進行兩次哈希。取結果的前四個字節作為校驗和。

  • 將校驗和附加到 version+PubKeyHash 的組合中。

  • 使用 Base58 對 version+PubKeyHash+checksum 組合進行編碼。

定義一個Wallets結構體,將wallet保存到本地文件wallet.dat中。

修改交易

交易輸入

#[derive(Debug, Serialize, Deserialize, Clone, Default)]pub struct Txinput {    txid: String,    vout: usize,    signature: Vec,    pub_key: Vec}
  • signature:交易發起方私鑰對交易進行的簽名

  • pub_key:交易發起方公鑰

簽名和驗簽

fn sign(&mut self, bc: &Blockchain, pkcs8: &[u8]) {    let mut tx_copy = self.trimmed_copy();    for (idx, vin) in self.vin.iter_mut().enumerate() {        // 查找輸入引用的交易        let prev_tx_option = bc.find_transaction(vin.get_txid());        if prev_tx_option.is_none() {            panic!("ERROR: Previous transaction is not correct")        }        let prev_tx = prev_tx_option.unwrap();        tx_copy.vin[idx].set_signature(vec![]);        tx_copy.vin[idx].set_pub_key(prev_tx.vout[vin.get_vout()].get_pub_key_hash());        tx_copy.set_hash();        tx_copy.vin[idx].set_pub_key(&vec![]);        // 使用私鑰對數據簽名        let signature = ecdsa_p256_sha256_sign_digest(pkcs8, tx_copy.id.as_bytes());        vin.set_signature(signature);    }}pub fn verify(&self, bc: &Blockchain) -> bool {    if self.is_coinbase() {        return true;    }    let mut tx_copy = self.trimmed_copy();    for (idx, vin) in self.vin.iter().enumerate() {        let prev_tx_option = bc.find_transaction(vin.get_txid());        if prev_tx_option.is_none() {            panic!("ERROR: Previous transaction is not correct")        }        let prev_tx = prev_tx_option.unwrap();        tx_copy.vin[idx].set_signature(vec![]);        tx_copy.vin[idx].set_pub_key(prev_tx.vout[vin.get_vout()].get_pub_key_hash());        tx_copy.set_hash();        tx_copy.vin[idx].set_pub_key(&vec![]);        // 使用公鑰驗證簽名        let verify = ecdsa_p256_sha256_sign_verify(            vin.get_pub_key(),            vin.get_signature(),            tx_copy.id.as_bytes(),        );        if !verify {            return false;        }    }    true}

驗證

先創建地址,將地址記錄下來。

let mut wallets = Wallets::new().unwrap();let genesis_addr = wallets.create_wallet();println!("==> genesis address: {}", genesis_addr);==> genesis address: 1M684nX5dTNQYi2ELSCazjyz5dgegJ3mVD

使用這個地址進行一筆交易

let justin_addr = "1M684nX5dTNQYi2ELSCazjyz5dgegJ3mVD";let mut wallets = Wallets::new().unwrap();let bob_addr = wallets.create_wallet();let path = current_dir().unwrap().join("data");let storage = Arc::new(SledDb::new(path));let mut bc = Blockchain::new(storage.clone(), justin_addr);let utxos = UTXOSet::new(storage);let tx_1 = Transaction::new_utxo(justin_addr, &bob_addr, 4, &utxos, &bc);let txs = vec![tx_1];bc.mine_block(&txs);utxos.reindex(&bc).unwrap();bc.blocks_info();

執行結果就不貼瞭,大傢自行驗證。

工程結構

完整代碼:

https://github.com/Justin02180218/blockchain_rust


更多文章,請關註公眾號:coding到燈火闌珊

本文來自網絡,不代表程式碼花園立場,如有侵權,請聯系管理員。https://www.codegarden.cn/article/31005/
返回顶部