一. 需求分析
总体需求:建立一个比特币钱包程序,能够完成获取学号、获取学号、挖矿、生成钱包这四个功能。
(1) 获取学号:使用10个ASCII码表示学号,由卡片向终端返还。
(2) 获取姓名:使用GB2312编码表示姓名,由卡片向终端返还。
(3) 挖矿:使用者发送一条数据,其中包含挖矿难度和交易数据两条信息。卡片在接收到命令后,进行工作量证明算法,向终端返还满足要求的数字。
(4) 生成钱包:使用者向卡片发送一条数据,其中包含公钥。卡片接收到命令后,对公钥地址进行双哈希算法,并将结果进行Base58编码,生成比特币地址并返还终端。
二. 程序设计
1. 总体框架:
final static byte myBTC_CLA = (byte) 0x80;
final static byte myBTC_NUMBER=(byte)0x81;
final static byte myBTC_NAME=(byte)0x82;
final static byte myBTC_DIG=(byte)0x83;
final static byte myBTC_PURSE=(byte)0x84;
2. 获取学号:
(1)通过ASCII码对照表,将学号对应表示为:
byte[ ] mynumber={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x38,0x38};
(2)将学号逐位放入APDU通信缓冲区,设置方向为卡片到终端后,设置数据发送长度,发送数据。
3. .获取姓名:
(1) 通过网络中的在线编码工具,转化为许下形式:
byte[ ] myname={0x0c,0x0e,0x0e,0x02,0x0c,0x0b,0x0b,0x06} ;
(2)将姓名逐位放入APDU通信缓冲区,设置方向为卡片到终端后,设置数据发送长度,发送数据。
4. 挖矿:
挖矿的总体思路很简单:
step1:从命令中获取挖矿难度和数据。
Step2:写一个计数器,从0开始计数。
Step3:将该数添加到数据的末尾,组成一个新的数组。
Step4:把这个新的数组进行SHA-1加密,获得20位的哈希值。
Step5:如果这个哈希值的前x位(x为难度,由p1送入)都是0,那么挖矿成功,返回这个计数值;否则,进入计数器的计数加1,重复(3)(4)直至挖矿成功或计数器上限溢出。
受javacard支持的数据格式的限制,只能够使用byte,short类型的变量或数组,给上述思路的实现带来了困难:
(1) 计数器的进位问题
计数器需要找到一个满足工作量证明的随机数,但byte型数据只有8bit,仅仅支持0x00~0xff的数字大小,显然是不够的。我们需要使用一个byte数组来存放这个随机数。此时产生了如何表示计数器进位的问题。
因为计数器位数固定为了4byte,所以降低了进位的表示难度。通过对几种低位计数到0xff时的临界状态的判定,解决进位问题。从最低位开始,到最高位,依次进行如下判断:当低位小于0xff时,低位加1;当低位需要进位时,高位加1,低位置0.
(2) 如何判断哈希值前x位为0的问题
hash值是用16进制数的形式来表示的,没办法简单的通过与固定的数做比较的方式确定0的个数。此处采用以循环左移位的方式,将哈希值与0x80相与。如果结果为0则说明该哈希值第一个bit为0。如此循环x位,便可得出前x位0的个数。设置一个变量用来记录0的个数,当相与结果为0时,该数加1;若有一个不为0的结果,该变量清0,退出循环,重新寻找随机数。
5. 生成钱包:
思路概述:
钱包的生成过程如流程图所示,在对公钥地址进行双哈希加密后获得公钥哈希,在对公钥哈希进行Base58Check编码,获得比特币地址。
在钱包的设计过程中,需要注意所用到的SHA-1、RIPEMD160、Base58checkd函数的输入输出数组的位数和格式。
具体流程如下:
(1)数组的说明
设置几个256byte的数组用于存储中间过程:
byte[ ] temp ,byte[ ] key, byte[ ] keytemp1, byte[ ] keytemp2
将最后的结果,及比特币地址存入byte[ ] keyfinal。
(2)生成流程
1.把buffer的data读进temp,对temp进行SHA-1存入key;
2.把key赋值给temp,并将temp补位至32位,进行temp,得到20位结果存入keytemp1;
3.在temp首位补0,之后放keytemp1的20位,对这21位进行SHA1,生成20位结果,存入key;
4.对key进行SHA1,结果存入keytemp2;
5.temp首位赋值00,跟上20位keytemp1,在加上keytemp2的前4位,组成25位;
6.对temp进行base58,结果存入keyfinal。
三.关键代码
1.工作量证明
(2)钱包生成过程
四、测试结果
(1)获取学号
(2)获取姓名
(3)挖矿
(4)生成钱包
五. 感谢
感谢 EdiblE 为本次程序提供的Javacard版的 RIPE160 和 Base58check 函数。
感谢 Mr. Chen 在修改bug方面提供的技术支持。