前言
在2014HITB-Exploiting ECDSA Failures in the Bitcoin Blockchain中他所使用提取签名的方法是通过Bloomfilter实现的,作者提到:
- first pass:把签名添加到Bloomfilter里面,作者所使用的是:dablooms,如果过滤器中已经存在了该签名,则把该签名放到一个map中叫做:potentialValues
- second pass:重新遍历signature,如果签名存在于potentialValues中,导出签名以及它的其他信息到map:rMap中
下面具体展开对源码的剖析
blockchainr
代码整体架构
- main函数
- btcdbSetup函数
- getSignatures函数
- search函数
getSignature
此函数的目的是导出区块中所有的Signature,作者定义了一个结构体,用于存放与签名相关的信息
type rData struct {
sig *btcec.Signature
H int64
Tx int
TxIn int
Data int
}
- sig:签名(包含r、s)
- H:交易所在区块的高度
- Tx:区块中的第几笔交易
- TxIn:交易中第几个TxIn
- Data:
该函数的返回值是这个类型:
func getSignatures(maxHeigth int64, log btclog.Logger, db btcdb.Db) chan *rData {}
具体过程就不说了,它主要就是通过一层层的循环将数据导出的(思想如下):
for block in chain:
for tx in block:
for input in tx:
...
search函数
使用dablooms这个Bloom过滤器,设置了容量、错误率等,都定义了常量
const (
tickFreq = 10
bloomSize = 100000000
bloomRate = 0.005
)
这里作者设置的容量是100000000,我觉得在2014年这个数据容量应该足够了
filter := dablooms.NewScalingBloom(bloomSize, bloomRate, "blockchainr_bloom.bin")
主要的提取过程前面提到了分为两步代码如下:
if step == 1 {
b := rd.sig.R.Bytes()
if filter.Check(b) {
matches++
potentialValues.Add(rd.sig.R.String())
} else {
if !filter.Add(b, 1) {
log.Warn("Add failed (?)")
}
}
} else if step == 2 {
if potentialValues.Contains(rd.sig.R.String()) {
matches++
rMap[rd.sig.R.String()] = append(rMap[rd.sig.R.String()], rd)
}
Signatures是调用getSignatures获得的,前文有提到过
signatures := getSignatures(maxHeigth, log, db)//获取签名
- 第一步,通过循环导出的signatures将签名R赋值给b然后通过过滤器过滤,判断签名是否在过滤器中出现过,如果出现过那么就把它添加到potentialValues中
- 第二步,再一次循环signatures判断R是否存在于第一步生成的集合potentialValues中,如果存在将其详细信息添加到rMap中,说一下rMap的类型:
rMap := make(map[string][]*rData)
key是string类型,value是rData类型,所以它的索引中存储的是签名R,value存储的是该签名R的其它信息。最后search函数返回rMap
main函数
首先给出了区块数据的路径以及数据库类型:
var (
dataDir = flag.String("datadir", filepath.Join(btcutil.AppDataDir("btcd", false), "data"), "BTCD: Data directory")
dbType = flag.String("dbtype", "leveldb", "BTCD: Database backend")
)
之后通过btcdbSetup函数设置了btcdb:
log, db, dbCleanup := btcdbSetup(*dataDir, *dbType)
再调用search函数导出区块中重复R的各个签名以及它们的相关信息
duplicates := search(log, db)//返回值是rMap
作者新定义一个与导出集合类型一致的map,(value是存储的该签名R相关的信息的一个数组,也就是说存储着多组不同的rData)这段代码非常重要,是作者整个思想的核心,通过循环判断value数组的长度是否大于一,若是则证明签名R是重复的,若不是则签名R不重复。
realDuplicates := make(map[string][]*rData)
for k, v := range duplicates {
if len(v) > 1 {
realDuplicates[k] = v
}
}
最后将上文代码中的realDuplicates导出成文件,至此完成了整个比特币网络中相同签名r及其相关信息的导出。