美文网首页
捅破区块链开发的那层窗户纸,钱包开发(一)

捅破区块链开发的那层窗户纸,钱包开发(一)

作者: 柏链教育 | 来源:发表于2019-07-29 17:45 被阅读0次

很多人都在说区块链改变世界,什么改变生产关系,这些都有点大。对于我们大众来说,真的能给我们实际的生活带来便利,这就是好的技术。区块链如果用好了,确实有可能在不久的将来给我们带来一些好处,但不管怎么带来好处,有一样东西大家起码要会用,这个东西就是钱包,它算是打开区块链世界的一扇窗户。也是大多数人接触区块链所使用的第一个产品,本文接下来会介绍钱包相关的一些概念,以及如何自己开发一个钱包。

钱包是什么

在我们传统印象中,钱包是放钱的。在当今世界来说,在大城市中生活的人们大多数已经不用钱包,钱包只是用来携带卡的。这就和我们区块链的钱包有些像了,区块链钱包是用来管理账户的,而那些账户的钱是存放在区块链网络上的。我们可以把钱包管理的地址理解为银行卡号,而钱是存在银行里的,说白了也就是一个数字。

image

钱包的分类

在区块链领域,钱包多种多样。如果按照运行环境区分,可以分为:浏览器钱包(metamask),手机钱包(imtoken),硬件钱包,纸钱包,脑钱包等。比较常用的还是浏览器钱包和手机钱包。

image

如果按照架构上区分,又可以分为普通钱包和HD(Hierarchical Deterministic 分层确定性)钱包。分层确定性钱包主要来源于比特币改进提案,也就是BIP协议,该协议后来演进为BIP32、39、44。

钱包有哪些概念需要了解呢

归纳起来,下述这些词汇是必须了解的,当然这是针对开发人员,如果仅仅是使用,要求没有这么高。

  • 私钥
  • 公钥
  • 地址
  • 助记词
  • 签名
  • 私钥存储

私钥是最核心的部分,有了私钥可以为所欲为。比特币或以太坊的私钥是通过椭圆曲线算法随机得到,通过私钥可以得到公钥,而公钥通过哈希计算可以得到地址,在比特币以及以太坊网络中,账户地址由公钥2次哈希得到。

助记词则来源于BIP协议的改进,主要原因是私钥不便于保存,因此引入住助记词的概念,通过12个英文单词可以推导出私钥。在BIP44协议中,主私钥可以推导出子私钥,子私钥可以推导出孙私钥,然后再进一步确定账户地址。

签名是区块链开发中的重要技术,只有当交易被签名了之后才不会被抵赖,同时签名也必须不能被伪造。而钱包必须提供的能力之一就是签名!

私钥存储同样有它的意义,因为私钥必须能保存下来,而那一串数字太难记忆,在区块链中,我们可以将私钥存储为keystore信息,这样就可以以文件的形式保存下来,同时指定一个keystore文件的打开密码,这样可以双重安全。

测试代码如下

助记词测试,需要借助bip39协议包,助记词的推导可以参考下图:

image

在图上,我们看到助记词获得需要2步,第一步是获取Entroy,第二步才是获得助记词,而助记词的神秘面纱其实也就是将Entroy前四位作为校验位放在后面,形成一个132bits的数据,将这些数据12等分切割,每份11bits,这些bits的0或1最终组成一个10进制数,而这个数字可以在助记词库中获得对应的单词。(助记词列表可以参考该链接:助记词库

// go get -u github.com/tyler-smith/go-bip39
func test_mnemonic() {
    //Entropy 生成
    b, err := bip39.NewEntropy(128)
    if err != nil {
        log.Panic("failed to NewEntropy:", err, b)
    }

    fmt.Println(b)

    //生成助记词
    nm, err := bip39.NewMnemonic(b)
    if err != nil {
        log.Panic("failed to NewMnemonic:", err)
    }
    fmt.Println(nm)
}

执行该函数,可以看到获得了12个助记词。

下面我们来验证一下,如果安装了ganache,会比较直观,它也是一个ether的钱包,属于图形化的钱包工具。我们可以将其助记词拷贝到代码中,用其去推导账户地址。测试代码如下:

func test_ganache() {
    nm := "august human human affair mechanic night verb metal embark marine orient million"

    // 助记词转化为种子 - > 账户地址
    // 先推导路径,再获得钱包
    path := MustParseDerivationPath("m/44'/60'/0'/0/0")

    wallet, err := NewFromMnemonic(nm, "")

    if err != nil {
        log.Panic("failed to NewFromMnemonic:", err)
    }

    account, err := wallet.Derive(path, false)
    if err != nil {
        log.Panic("failed to Derive:", err)
    }

    fmt.Println(account.Address.Hex())

    path = MustParseDerivationPath("m/44'/60'/0'/0/2")

    account, err = wallet.Derive(path, false)
    if err != nil {
        log.Panic("failed to Derive:", err)
    }

    fmt.Println(account.Address.Hex())

}

上述代码中,关键要对m/44'/60'/0'/0/0加以理解,这是以太坊账户地址的路径,也是前面介绍分层确定性钱包特有的。m代表master主私钥,44代表协议版本,60代表币种,如果是0则表示比特币,60代笔以太币,接下来的0‘代表账户,后面0代表子层编号,最后0代表子层的账户编号,具体格式如下:m/purpse'/coin_type'/account'/change/address_index。

image

我们在代码中推导主要先用路径推导得到path,然后将path传递给Derive函数就可以得到对应的账户地址。大家可以通过修改address_index来测试推导不同的账户地址,是否可以和ganache初始化的地址一致。

接下来我们再来介绍一下如何存储私钥,也就是保存为keystore文件。

func test_keystore() {
    nm := "august human human affair mechanic night verb metal embark marine orient million"

    // 助记词转化为种子 - > 账户地址
    // 先推导路径,再获得钱包
    path := MustParseDerivationPath("m/44'/60'/0'/0/0")

    wallet, err := NewFromMnemonic(nm, "")

    if err != nil {
        log.Panic("failed to NewFromMnemonic:", err)
    }

    account, err := wallet.Derive(path, false)
    if err != nil {
        log.Panic("failed to Derive:", err)
    }

    fmt.Println(account.Address.Hex())
    //得到私钥
    pkey, err := wallet.derivePrivateKey(path)

    if err != nil {
        log.Panic("failed to derivePrivateKey:", err)
    }

    fmt.Println(*pkey)

    key := NewKeyFromECDSA(pkey)

    hdks := NewHDKeyStore("./data")

    err = hdks.StoreKey(hdks.JoinPath(account.Address.Hex()), key, "123")
    if err != nil {
        log.Panic("failed to StoreKey:", err)
    }

}

这需要修改以太坊的部分代码,自行封装一个包,然后调用以太坊官方的私钥转json算法,最终形成一个json字符串存储在keystore文件中.

{
    "address": "aa81dc6057a30e4a13f45c41822ab1ddd4e01f87",
    "crypto": {
        "cipher": "aes-128-ctr",
        "ciphertext": "93e7d2bf85024b799281440b5b135af5b4e3fd8127b716427160b39c06ec8d55",
        "cipherparams": {
            "iv": "50ef4c9002b3eb5cd9579a89c35df478"
        },
        "kdf": "scrypt",
        "kdfparams": {
            "dklen": 32,
            "n": 262144,
            "p": 1,
            "r": 8,
            "salt": "92a2aad76666fd04fe76603b13d20ac9165f8091c9d184c6ff3a863e93e9aa88"
        },
        "mac": "ba72448077803aff28e6f10d0d8d7538845840e0888dad6a2ab0d5a633a650d7"
    },
    "id": "308cb593-b920-4485-9726-6a7093a4d43e",
    "version": 3
}

这个文件中有账户地址,ciphertext就是加密后的密文,如果想解析并且使用该文件,必须知道创建该文件时指定的密码,当密码正确时可以解析得到正确的mac值,否则解析就会失败。

上述源码可以在此处下载:下载地址

相关文章

网友评论

      本文标题:捅破区块链开发的那层窗户纸,钱包开发(一)

      本文链接:https://www.haomeiwen.com/subject/bbkirctx.html