上一篇我们实现了交易,在这一部分我们通过非对称加密算法生成密钥对、对交易进行签名、验签等操作。
钱包
包含公钥和私钥两个字段
#[derive(Serialize, Deserialize, Clone)]
pub struct Wallet {
pkcs8: Vec<u8>,
public_key: Vec<u8>,
}
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<u8> {
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<u8> {
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<u8> {
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<u8>,
pub_key: Vec<u8>
}
签名和验签
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<T: Storage>(&self, bc: &Blockchain<T>) -> 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到灯火阑珊
|