前言
本篇介绍比特币“挖矿”算法简化模拟的模型,为博主学习密码学老师给出的作业,代码仅供参考。
一、比特币“挖矿”简介
比特币(Bitcoin)是一种由开源的P2P软件产生的网络虚拟货币。它不依靠特定货币机构发行,通过特定算法的大量计算产生,比特币经济使用整个P2P网络中众多节点构成的分布式数据库来确认并记录所有的交易行为。P2P的去中心化特性与算法本身可以确保无法通过大量制造比特币来人为操控币值。
比特币系统由用户(用户通过密钥控制钱包)、交易(交易都会被广播到整个比特币网络)和矿工(通过竞争计算生成在每个节点达成共识的区块链,区块链是一个分布式的公共权威账簿,包含了比特币网络发生的所有的交易)组成。
比特币矿工通过解决具有一定工作量的工作量证明机制问题,来管理比特币网络—确认交易并且防止双重支付。由于散列运算是不可逆的,查找到匹配要求的随机调整数非常困难,需要一个可以预计总次数的不断试错过程。这时,工作量证明机制就发挥作用了。当一个节点找到了匹配要求的解,那么它就可以向全网广播自己的结果。其他节点就可以接收这个新解出来的数据块,并检验其是否匹配规则。如果其他节点通过计算散列值发现确实满足要求(比特币要求的运算目标),那么该数据块有效,其他的节点就会接受该数据块。
中本聪把通过消耗CPU的电力和时间来产生比特币,比喻成金矿消耗资源将黄金注入经济。比特币的挖矿与节点软件主要是透过点对点网络、数字签名、交互式证明系统来进行发起零知识证明与验证交易。每一个网络节点向网络进行广播交易,这些广播出来的交易在经过矿工(在网络上的计算机)验证后,矿工可使用自己的工作证明结果来表达确认,确认后的交易会被打包到数据块中,数据块会串起来形成连续的数据块链。每一个比特币的节点都会收集所有尚未确认的交易,并将其归集到一个数据块中,矿工节点会附加一个随机调整数,并计算前一个数据块的SHA256散列运算值。挖矿节点不断重复进行尝试,直到它找到的随机调整数使得产生的散列值低于某个特定的目标 。
(图源:网络)
(资料:百度百科)
二、算法简化模拟
1.题目
参数:哈希函数采用SHA-256;挖矿难度为整数d(>0),代表哈希值前导字符串为0的数量,d值越小难度越小,d值越大难度越大
- 随机生成一个整数x
- 对x生成哈希值h=H(x)
- 对h的前导字符串进行判定:如为d个0则挖矿成功;否则回到步骤1
输出:d=1,2,3,4,5时挖矿成功耗时(可取3组数平均值)
2.题目分析及模块介绍
①随机数模块
产生随机数,可以使用到numpy
这个模块里面的函数random.randint(a,b)
产生位于区间[a,b)内的随机整数。
import numpy as np
②哈希函数模块
要使用哈希函数SHA-256加密,可以使用hashlib
模块中的sha256()
加密。
hashlib
模块中还提供了ha1()
、sha224()
、sha384()
、sha512()
和blake2b()
、blake2s()
、md5()
等加密算法。
import hashlib as ha
使用sha256加密,需要先用str()
将随机数x转换成字符串,再使用string.encode('utf-8')
对字符串使用utf-8
编码,再通过update()
加载进去,最后使用hexdigest()
获取加密后的哈希值。
③计时模块
在python中,时间模块time
提供time.perf_counter()
的方法返回当前代码运行时间(包括系统休眠的时间),也可以适用time.time()
的方法,返回系统时钟的时间戳(1970纪元后经过的浮点秒数)。
通过开始挖矿到挖矿成功返回的两次时间值之差可以计算代码运行即挖矿的时间。
import time
3.编写代码
按照题目要求及分析编写代码。
import numpy as np
import hashlib as ha
import time
t=[]#存储挖矿时间
def find_gold(d):
startTime = time.perf_counter()#记录开始时间
text=""
for i in range(0,d):
text = text + '0'
n = 1
while True:
x = np.random.randint(0,100000000)
string = str(x)#随机数x转换为字符串
utf_str=string.encode('utf-8')#进行'utf-8'编码
h = ha.sha256() #采用sha256加密
h.update(utf_str) #加载数据
b = h.hexdigest() #获取哈希值
n= n + 1#计算次数
if b[0:d] == text:
costTime = time.perf_counter() - startTime#耗时=结束时间-开始时间
print('随机数:{}'.format(x),'用时:{}'.format(costTime))
print('哈希值:%s'%b)
print('挖矿次数:%d'%n)
print('挖矿成功!')
break;
t.append(costTime)#将此次耗时加入列表中
if __name__ == '__main__':
for d in range(1,6):
print('挖矿难度d:%d'%d)
for i in range(0,3):
find_gold(d)
average_t = sum(t[3*(d-1):3*d]) / 3.0
print('平均时间:{}'.format(average_t))
print('\n')
4.运行结果
运行结果如下:
5.思考
题目要求的是取三次平均,但经过多次试验,d=5时成功挖矿一次可能用时十几秒,也可能少于一秒,随机性比较大,若要统计平均时间需要更多的数据。
总结
通过这个题目,了解了“挖矿”算法,通过学习也了解了time模块和hsahlib模块,完成了作业。
一开始我设置的随机数比较小,在0~10之间,导致d=1跑了很久都跑不出来,并且由于啥都不懂,增加了一堆print语句,输出了哈希值,每次的随机数等等便于查看,严重拖长了运行时间,一度以为是算法的原因。后经与同学讨论后改用了较大的随机数,随机数较大其产生的哈希值字符串较长,更容易成功匹配,一步步尝试越取越大,了解清楚原理后把所有的print语句都删了,节约了时间。