Bitcoin Core是根正苗红的比特币全节点钱包软件,由创始人中本聪最早完成,编程语言是C ,对于一些现代程序员来说,理解起来有一定难度,所以有些开发者将这些代码移植为其它编程语言。
Bitcoin在.NET平台的一款实现就是今天要介绍的NBitcoin,项目站点:
https://github.com/MetacoSA/NBitcoin
我使用的软件集成开发平台是Visual Studio 2015,.Net Framework是4.5.2。
安装NBitcoin引用
我建立了一个控制台应用HelloBitcoin,需要添加NBitcoin类库的引用,最方便的办法是用NuGet,操作办法见下图,注意可能需要访问外国网站。
安装过程中,会对整个解决方案的依赖类库进行一系列修改, 并且让你接受软件许可授权,可能涉及到的类库:
Newtonsoft.Json 11.0.2
System.Buffers 4.5.0
System.Collections 4.0.11
System.Collections.Concurrent 4.0.12
System.Diagnostics.Debug 4.0.11
System.Globalization 4.0.11
System.Linq 4.1.0
System.Net.Http 4.3.3
System.Net.Requests 4.3.0
System.Reflection 4.1.0
System.Resources.ResourceManager 4.0.1
System.Runtime.Extensions 4.1.0
System.Runtime.InteropServices 4.1.0
Microsoft.Extensions.Logging.Abstractions 1.0.2
最后在调试输出窗口中出现这样一行:
已将“NBitcoin 4.1.1.71”成功安装到 HelloBitcoin
表示NBitcoin安装成功。
用私钥生成比特币地址
下面一段简单的代码用来将一串私钥生成为比特币地址,请与《我生成的比特币地址竟然与别人的重合了》这篇文章一起参考阅读。
程序开头不要忘记这一行:
using NBitcoin;
直接上代码:
简要解释说明一下:
privKeys是私钥,为256位二进制数,NBitcoin中与私钥对应的类是Key。
下面这行语句生成一个随机私钥。
Key k = new Key();
私钥可以生成公钥,再生成比特币地址,借用一下《精通比特币》中的这张原理图。
Network.Main表示使用比特币的真实主网络,直接用真金白银的BTC调试程序太奢侈,可以切换到测试网络Network.TestNet。
程序最终输出:
19t4GGYorFziM26CRMYvxqvDw6NPhuCRJS
对应于BitcoinExplorer工具的命令行是:
bx ec-to-public 3243......E6C8 | bx bitcoin160 | bx address-encode
可以看到,最后生成的比特币地址是一致的。
压缩公钥、非压缩公钥
一个私钥实际上可以产生出两种不同的比特币地址,这个问题有点迷惑人,但这是由于椭圆曲线的特性造成的,先看代码。
k1生成出来的是压缩公钥:
为了方便阅读,我人为插入了空格。
02 2e88d239fb78cee0c1c55943a96dcc8b70adf47e18b53f9ba110b6fb871e1f8b
k2对应于非压缩公钥:
请注意与上面的区别。
04 2e88d239fb78cee0c1c55943a96dcc8b70adf47e18b53f9ba110b6fb871e1f8b b119f9161df032167181d623a401dde4091c3e0be2001e4dea3e1f53f851aa3a
拆开说明这一长串数字的具体含义:
04 // 表示非压缩公钥
2e88d239fb78cee0c1c55943a96dcc8b70adf47e18b53f9ba110b6fb871e1f8b // 椭圆曲线上点的X坐标
b119f9161df032167181d623a401dde4091c3e0be2001e4dea3e1f53f851aa3a // 椭圆曲线上点的Y坐标
椭圆曲线有一个重要特性,它是以X轴为对称轴的,这样记录一个点的坐标时,只需要记录X坐标,省略Y坐标,只需要知道Y坐标的正负号,就可以根据X计算出Y。
在二进制的椭圆曲线运算中,没有正负号,但有奇偶性,只记录X坐标及奇偶性,就是压缩公钥的表示法,刚才的那个公钥就可以节省一半的存储空间。
02 // 表示压缩公钥,Y坐标为偶数
2e88d239fb78cee0c1c55943a96dcc8b70adf47e18b53f9ba110b6fb871e1f8b // 椭圆曲线上点的X坐标
两种公钥表现形式不一样,生成的比特币地址当然就不一样:
地址1:
19t4GGYorFziM26CRMYvxqvDw6NPhuCRJS
地址2:
17mKugcBDEJbu391Fq41AdwLeGHwJLPRDf
比特币的交易信息中经常存储公钥,压缩公钥节省了大量存储空间,意义重大,后来的钱包软件主要都使用压缩公钥,也就是常用上面的地址1。
19t4GGYorFziM26CRMYvxqvDw6NPhuCRJS
WIF钱包导入格式
私钥是一长串数字,比如:3243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C8,输入费劲,还容易出错,中本聪就规定了一种WIF格式,称为Wallet Import Format,这种格式的私钥可以非常方便地导入到Bitcoin Core等钱包软件中。
用GetWif()函数可以非常容易地得到WIF格式的私钥。
以K开头的为压缩表示法:
KxuRLWqnfcgs8ru7YiMBfP6T71jK9twCedaeBtHgRgzb8adnoZzH
以5开头的是非压缩表示法,但本质上两个私钥是一模一样的:
5JCRYcJrKGLTK6R3PbHopfY9BRdmtrq5TCTesx7x9mQUDeYDfZj
P2SH地址、隔离见证地址
前面见到的比特币地址都是以1开头的:
19t4GGYorFziM26CRMYvxqvDw6NPhuCRJS
17mKugcBDEJbu391Fq41AdwLeGHwJLPRDf
很多人现在看到的是以3开头的地址,这种地址术语是P2SH地址,即Pay-to-Script Hash地址,这类地址是由交易脚本创建的,具体原理先不用了解,代码很方便。
pk1.GetScriptAddress(Network.Main)
结果是这样的:
33yjfa31iqdDRqHqQRuvySB7SVV7wd77aj
后来又出来了隔离见证地址,采用Bech32格式编码。
pk1.GetSegwitAddress(Network.Main)
样子是这样的: bc1qv950rspcgfqufasc29calr5qphh4ucl3ur7vnm
看到这样的地址别以为收到了假比特币。
以前在给多个人发币时,使用NBitcoin时踩了一些坑:
- 同时给200多人发送比特币,程序员是这样做到的
当时想参考NBitcoin的API文档:
https://metacosa.github.io/NBitcoin/api/index.html
可惜文档非常糟糕,还不如果直接看源代码,几乎是边google边试错完成了程序。
所以我准备把更详细的使用方法逐步整理出来,请留言或点赞,给我助力。
--- END ---