在前面的课程中,我们使用节点软件的getnewaddress调用来创建 新的比特币地址,地址对应的私钥以及交易的签名都是由节点钱包模块 管理,应用程序是无法控制的,在某些应用场景中,这可能会限制 应用的功能实现。
如果要获得最大程度的灵活性,我们就需要抛开节点软件,使用 C#代码来离线生成地址。这些离线生成的地址自然不属于节点钱包 管理,因此也会带来一些额外的问题,例如:
需要我们理解密钥、地址、脚本这些比特币内部的机制
需要我们自己进行裸交易的构造以及签名,而不是简单地调用sendtoaddress
需要我们自己跟踪这些地址相关的UTXO,而不是简单地调用listunspent
需要我们自己汇总比特币余额,没有一个getbalance可用
这些麻烦都是因为我们试图自己管理地址而引发的,从某种程度上说, 一旦我们决定自己管理地址,基本上就需要实现一个钱包模块了:
在接下来的课程中,我们还是使用NBitcoin来完成这些任务 —— 前面说过,NBitcoin 是最完善的.NET平台上的比特币协议实现,它不仅仅包含RPC的封装。
二、创建私钥和公钥
我们之前已经了解,从私钥可以导出公钥,从公钥则可以导出地址,地址只是 公钥的一种简明表达形式:
私钥本质上就是一个随机数,从私钥出发,利用椭圆曲线乘法运算 可以推导出公钥,而从公钥,利用哈希算法就得到比特币地址了。这两次 运算都是单向不可逆的,因此无法从地址反推出公钥,或者从公钥反推出 私钥。
地址源于密钥,因此让我们首先使用NBitcoin的Key类来创建公钥和私钥:
例如,下面的代码创建密钥对并显示私钥和公钥的16进制字符串:
Key key = new Key(); Console.WriteLine("is compressed => {0}",key.IsCompressed); //是否压缩公钥? string prv = Encoders.Hex.EncodeData(key.ToBytes()); //16进制字符串 Console.WriteLine("private => {0}",prv); Console.WriteLine("private wif => {0}",key.GetWif(Network.RegTest)); //WIF格式私钥 PubKey pubKey = key.PubKey; //返回公钥对象 Console.WriteLine("public => {0}",pubKey.ToHex()); //16进制字符串