比特币入门-1-钱包

钱包 【比特币入门-1-钱包】将身份验证,财产验证,等等问题综合起来,就实现了钱包。
首先我们要了解私钥和公钥,这是钱包信息保密和验证的基础
私钥 公钥

  • 私钥是一个随机选出来的 256 位的二进制数,一共可以随机生成的秘钥数量大概和宇宙中的原子差不错,随机生成两个相同的私钥概率,等同于随机在宇宙中抓两个原子,他们是一样的
  • 通过私钥(其实就是足够大的随机数)生成公钥有多种算法,比特币使用椭圆曲线算法,可以从私钥得到一个坐标(x,y),相加得到公钥。因为其中的数学运算是单向的,所以私钥可以转换为公钥,但公钥不能转换回私钥
  • 公钥和私钥之间的数学关系,可以使私钥生成特定消息的签名。此签名可以在不暴露私钥的情况下用公钥验证,而其他私钥无法生成类似的签名。签名不可伪造,且每次都会生成不一样的签名
公式警告!: 签名 = f1(私钥,hash(数据)) hash = f2(公钥,签名) //保证数据的唯一性,就能保证签名的唯一性,使得其他人无法伪造签名,但是所有人都能检验签名 //具体签名实现会在交易部分介绍

  • 私钥和公钥是复杂难以记忆的,可以使用 Base64 等编码方式使其易读性,并减少数据量,编码只提高可读性,可以解码得到原始值,还有其他的方式对私钥进行压缩,减少数据库存储量,使用时再计算私钥,这里不再介绍。但是,无论是哪种方式,最终都要得到私钥。
  • 谁掌握了私钥,就掌握了它对应的比特币的所有权和控制权
// 一个账户,包含一个公钥和私钥 type Wallet struct { PrivateKey ecdsa.PrivateKey PublicKey[]byte }func NewWallet() *Wallet { pri, pub := newKeyPair() return &Wallet{pri, pub} }// 生成一对公钥和私钥 func newKeyPair() (ecdsa.PrivateKey, []byte) { //创建一个椭圆 curve := elliptic.P256() //使用椭圆和随机数生成私钥和公钥 privateKey, err := ecdsa.GenerateKey(curve, rand.Reader) util.ErrLogPanic(err) pubkey := append(privateKey.PublicKey.X.Bytes(), privateKey.PublicKey.Y.Bytes()...)return *privateKey, pubkey }

这种不对称加密的技术是比特币的基石,不过即使这个数学问题被人破解了,仍可以用硬分叉的方式改变这种底层验证
地址 地址等同于账户,在交易中,必须有付款和收款的唯一证明,地址就是收款身份证明
地址 = Base58check( RIPEMD160( version + SHA256( 公钥 ) ) + 校验和 )
RIPEMD160 和 SHA256 是两个哈希函数,Base58check 是一种可验证易读的编码方式
Base58check 编码过程
  1. Base64使用了26个小写字母、26个大写字母、10个数字以及两个符号(例如“+”和“/”),Base58是Base64编码格式的子集,舍弃了一些容易错读和在特定字体中容易混淆的字符
  2. RIPEMD160( SHA256( 版本 + 传入函数的数据 ) ),生成值后获取前四位,作为校验码,加入校验和是为了确保地址在传输过程中不会出错和,并可以检验地址格式是否正确,版本号则防止以后地址算法的改变
  3. 编码后生成:版本 + 数据 + 校验码,通过校验码可以验证前面两个数据是否正确。这样在传输中,一旦有信息丢失,可以通过校验码计算,检验出来。也可能会存在前面的数据部分丢失,但生成相同的校验码,但是这个概率太小,不会频繁出现,对众多节点的传播不会造成太大影响
对私钥和公钥也有不同的编码方式进行压缩,但是无论如何压缩,只要有具体的编码方式,最终还原的到的必定是相同的私钥和公钥
//生成地址(账户) func (w Wallet) GetAddress() []byte { //为 pubkey 做 hash 运算 pubkeyHash := HashPubKey(w.PublicKey)//插入版本号和校验和 versiondPayload := append([]byte{version}, pubkeyHash...) checksum := checksum(versiondPayload) fullPayload := append(versiondPayload, checksum...)//以 base58 进行编码 address := util.Base58Encode(fullPayload) return address } //校验和 func checksum(payload []byte) []byte { sha1 := sha256.Sum256(payload) sha2 := sha256.Sum256(sha1[:])return sha2[:addressChecksumLen] }

你可能会有疑问,既然公钥不能计算出私钥,而要使用公钥验证私钥,为什么不把公钥作为账户地址呢?
这是中本聪对未来量子计算的考虑,“公钥不能推导出私钥” 这一表述不太正确,在目前的算力下无法计算出,但是以后有了量子计算,算力飙升,就可能从公钥推导出私钥,而 hash 操作无法逆运算(就算能,难度也提升了好几个等级了),这样就进一步保证了私钥的安全
钱包结构 一切加密,证明和验证都是基于私钥的,所以也可以认为钱包就是私钥的容器,它既可以存在一个文件中,也可以放在数据库里,请记住:无论是哪种形式的钱包都只是为了更好的保持秘钥
钱包有很多实现方式
  • 非确定性钱包:所有的私钥都是随机生成的,对有多个钱包的人来说,非常不利于迁移,要记录的也很多
  • 确定性钱包:每生成一个钱包都是通过最后生成的钱包计算 SHA256 得到的,这样只需要记住第一个钱包,就能推导出所有的钱包
    • 其他的一些通过将随机数编码使得容易记忆的钱包:常用的是助词码钱包,
    • 分层确定性钱包:由种子得到主秘钥,主秘钥可以繁衍出树状秘钥
为了私钥的安全,诞生了各式各样的钱包保存手段,他们不属于比特币的核心内容,这里就不再介绍

    推荐阅读