比特币“工作量证明”鼻祖——hashcash 算法

比特币“工作量证明”鼻祖——hashcash 算法

比特币的架构,在技术上可谓是集大成于一家。比如分布式系统、去中心化、非对称加密、工作量证明等等。

本篇聊聊最早提出的工作量证明的应用——hashcash,有翻译:比特币现金,本文还是沿用原名hashcash。

而它最早构想,是应用在电子邮件内,用于防止垃圾邮件的一个机制。

而比特币的工作量证明,基本就是借鉴了这个思路。

垃圾邮件的泛滥

虽然现在国内,即时聊天(如QQ、微信)大大取代了电子邮件,但是在“万恶的资本主义”世界内,电子邮件还是最受青睐的一个通讯工具。

在早期,即时聊天还没有诞生的时候,电子邮件更是最重要的点对点通信工具。电子邮件作为主要的通讯工具,自然是营销人员最喜爱的推广工具。

只要知道对方邮箱便可往对方邮箱塞东西了,架一个脚本,搞个电子邮件的群发、盲发、批量并发营销邮件——也就是垃圾邮件,这对于电子邮件发送方来说,基本是毫无代价的。

而在接受方,垃圾邮件就是人们非常头痛的一个事情了:它常常可以把正常的邮件冲得“落花流水春去也”。

让发邮件有代价:工作量证明

电子邮件,没有邮票这一说,否则,要求发邮件贴几分钱邮票,垃圾邮件都没有那么猖狂了。

于是,一些技术大牛就会想:有没有一种办法,让邮件发送方需要付出一些代价才可以发送一封邮件,而接收方可简单的验证邮件是否是合法的?

牛人Adam Back的一篇论文《Hashcash – A Denial of Service Counter-Measure》(连接文章末尾),于1997年首次提出。

Hashcash 的做法就是这样:要求发给我的电子邮件header中包含一个stamp(戳记),这个标记需要进行大量计算才可生成,格式如下:

也就是说,所有发送给我的邮件,需要带上一个这样的X-Hashcash(也就是前面的stamp),需要满足:

1 sha-1(X-hashcash) 的前面0的个数,大于X-hashcash.bits 的值(比如20);

2 X-hashcash.date 和当前时间不能超过2天(主要是为了防止服务器之间时间差异或者网络延时);

3 X-hashcash.resource 指明是我的电子邮箱(或者其他如IP、URI); 

4 每个X-hashcash 只能用一次(我会记录以前是否有使用过该值)。

我们看一个合法的stamp:

X-Hashcash: 1:20:13030X30600:adam@cypherspace.org::McMybZIhxKXu57jd:ckvi

我们先来构建代码看看,如果要发送邮件给 10001@gamil.com,bits为20,我们测试下计算一个X-hashcash 需要的时间,代码:

from time import strftime, localtime, time
from math import ceil, floor
import hashlib

def _mint(challenge, bits):
    hex_digits = int(ceil(bits/4.))
    zeros = '0'*hex_digits

    end_chars = ""
    counter = 0
    while 1:
        end_chars = hex(counter)[2:]
        digest = hashlib.sha1((challenge+end_chars).encode()).hexdigest()
        if digest[:hex_digits] == zeros:
            print("运算了:%d 次!" % counter)
            return end_chars

        counter += 1


def mint(resource, bits, ext, salt):
    ts = strftime("%y%m%d%H%M%S", localtime(time()))
    ver = "1"

    challenge = "%s:"*6 % (ver, bits, ts, resource, ext, salt)
    return challenge + _mint(challenge, bits)

start = time() * 1000
# 偷懒,写死salt为 "1QTjaYd7niiQA/sc"
x_hashcash = mint("10001@gamil.com", 20, "", "1QTjaYd7niiQA/sc")

end = time() * 1000

print("用时:%d ms, \nX-hashcash:" % int(end - start))
print(x_hashcash)

执行结果:

如上测试代码,发送方构造一个邮件X-hashcash头,在要求bits为20情况下,计算了1541662次hash值,用时是2351毫秒(2.3秒),bits 可随着硬件提升而可约定增加。

如何抵制了垃圾邮件?

1)垃圾邮件发送方

由于没有很方便的计算符合条件的X-hashcash的方法,所以,只有如上代码那样,进行枚举一个一个地算其hash值,直到逮到一个满足条件的值为止。这个是非常耗算力的。前面文章提到过《一分钟了解,比特币知识,为什么比特币挖矿那么费电》也是一样意思。

但对于垃圾邮件来说,他们期望发送邮件,是海量的发送的,数十甚至上百封邮件一秒。由于需要计算大量的X-hashcash,其垃圾邮件效果就大大受挫了。达到抵制垃圾邮件内容的效果。

2)对于正常邮件发送方

这个计算时间对于正常的邮件发送者,是可以接受的,因为填好邮件接收方,计算机便可开始计算X-hashcash 头了,邮件编辑者同时可以编辑邮件内容。就算是数秒的计算可以说无所谓。

3)对于邮件接收方

而对于邮件接收方来说,验证其hash值是非常方便的,验证X-hashcash都不用1毫秒(用前面的:1541662次hash值,用时是2351毫秒,0.0015ms)不管bits调整到多少位,验证时间都是几乎不变。

也就是引入hashcash的系统,正常的邮件发送方和接受方,都没有太大的成本,但对于垃圾邮件发送者来说,大量的计算会“劝退”一大帮了。

最成功的应用:比特币

目前为止,hashcash的最成功应用,就数比特币了,比特币使用类似hashcash算法来作为矿工的工作量证明。

中本聪也没有照搬hashcash,而做了调整:

* 使用了强度更好的sha256(256位)代替sha1(160位);

* 为了更好的安全性,中本聪是hash运行了两次;

* hashcash中的bits 在比特币中,使用了共识周期性动态调整,使得区块创建率不变(10分钟出块)。

hashcash 的缺点

毫无疑问,和比特币一样,其缺点就是浪费cup算力了,只是对于正常的某个邮件发送方来说,这单算力是可以不计较,但是全球亿计的正常邮件在传输,这个算力总体来说,就是一个浪费了。

参考资料:

David Mertz, Ph.D.实现的Python版本的hashcash:

http://www.gnosis.cx/download/gnosis/util/hashcash.py

wiki百科:

https://en.wikipedia.org/wiki/Hashcash

Hashcash – A Denial of Service Counter-Measure:

http://www.hashcash.org/papers/hashcash.pdf

(全文完)

(欢迎转载本站文章,但请注明作者和出处 云域 – Yuccn

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注