上一篇我們實現瞭交易,在這一部分我們通過非對稱加密算法生成密鑰對、對交易進行簽名、驗簽等操作。
錢包
包含公鑰和私鑰兩個字段
#[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到燈火闌珊