review:UTXO和余额模型到底有没有区别?
有,举个例子,比如小红转我80元,小绿转我20元,我再转50元给了小黑。
UTXO模型
可以明确的告诉我,我转给小黑的50元到底是来自小红给我的80元加找零,还是小绿的20元加上小红给我的80元加找零。
余额模型
却无法做到可追溯,因为我转给小黑50元,是我的余额减50,小黑的余额加50,然后产生一笔交易记录(我->小黑:50元),不能确定我转出去的50来自谁。
引言
在比特币中,没有用户账户
,不需要,也不会在任何地方存储个人数据(比如姓名,电话,身份信息等)。
但我们必须要能够实现交易的输出者可以使用这比交易,用官方的话来说,就是你拥有在这些输出上锁定的币。
这一节,我们将要实现一个跟比特币一样的真实地址address。
需用用到的知识:
- 公钥加密
- 数字签名
- base58算法
公钥加密
公钥加密(public-key cryptography)算法使用的是成对的密钥:公钥和私钥。私钥加密公钥解密,或者公钥加密私钥解密。
在加密货币的世界中,你的私钥代表的就是你,私钥就是一切。
比特币钱包也只不过是这样的密钥对而已。
比特币使用椭圆曲线
来产生私钥。
数字签名
签名过程:
hashData = hash(data)
加密的hashData = 私钥加密(hashData)
(data+加密的hashData) 一起发给接受方
验证的过程:
hashData_1 = hash(data)
hashData_2=公钥解密(加密的hashData)
if hashData_1 == hashData_2 : 验证通过
数字签名特点:
- 当数据从发送方传送到接收方时,数据不会被修改;
- 数据由某一确定的发送方创建;
- 发送方无法否认发送过数据这一事实。
在比特币中,每一笔交易输入都会由创建交易的人签名
。在被放入到一个块之前,必须要对每一笔交易进行验证
。
Base58
比特币使用 Base58 算法
将字节串转换成人类可读的形式。
Base58算法是可逆的,我们对数据进行Base58编码后,可以解码还原成原来的数据。
比特币地址的产生
我们设pubKey=公钥
- hash_1 = SHA256(pubKey) //对公钥进行第一次hash
- hash_2 = RIPEMD160(hash_1) // 对hash_1进行hash
- versionedPayload = version + hash_2 //byte拼接
- hash_3 =SHA256(SHA256(versionedPayload )) // 再对versionedPayload 进行两次hash
- s = version(1字节) + hash_2(20字节) + hash_3(前4字节) //三个byte拼接
- address = Base58Encode(s) //对s进行base58编码,转成人类可读的字符串
s字符串:
Version Public key hash Checksum
00 62E907B15CBF27D5425399EBF6F0FB50EBB88F18 C29B7D93
最终加密结果
1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa \\ 属于中本聪
图:
代码实现
//钱包
type Wallet struct {
Privatekey ecdsa.PrivateKey \\私钥
PublicKey []byte \\公钥
}
//新建一个钱包
func NewWallet() *Wallet {
private, public = 椭圆曲线生成公私钥
wallet := Wallet{private, public}
return &wallet
}
const versionByte = byte(0x00)
const addressChecksumLen = 4
//获得地址
//address = base58(version + publickey hash + checksum)
func (w Wallet) GetAddress() []byte {
//RIPEMD160(SHA256(pubKey))
pubkeyhash := HashPubkey(w.PublicKey)
//versionByte + RIPEMD160(SHA256(pubKey))
versionedPayload := append([]byte{versionByte}, pubkeyhash...)
// sha256(sha256(versionByte + RIPEMD160(SHA256(pubKey))))
checksum := checksum(versionedPayload)
//versionedPayload + checksum
fullPayload := append(versionedPayload, checksum...)
//base56
address := Base58Encode(fullPayload)
return address
}
这就是为什么选择一个合适的公钥加密算法是如此重要:考虑到私钥是随机数,生成同一个数字的概率必须是尽可能地低。理想情况下,必须是低到“永远”不会重复。
这个算法有一个好处,就是可以通过address推出收货人的公钥hash值。
以这个为基础,我们就可以对交易的input和output进行锁定
/解锁
和签名
等操作。