去,中间状态SHA-256哈希

时间:2012-02-12 00:11:15

标签: hash go state sha256 sha

拥有128个字节的数据,例如:

00000001c570c4764aadb3f09895619f549000b8b51a789e7f58ea750000709700000000103ca064f8c76c390683f8203043e91466a7fcc40e6ebc428fbcc2d89b574a864db8345b1b00b5ac00000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000

并且想要在其上执行SHA-256哈希,必须将其分成两个64字节的数据并在将结果一起散列之前单独散列它们。如果要经常更改数据后半部分的某些位,可以简化计算并仅将前半部分数据哈希一次。如何在Google Go中做到这一点?我试着打电话

func SingleSHA(b []byte)([]byte){
    var h hash.Hash = sha256.New()
    h.Write(b)
    return h.Sum()
}

但不是正确答案

e772fc6964e7b06d8f855a6166353e48b2562de4ad037abc889294cea8ed1070

我得到了

12E84A43CBC7689AE9916A30E1AA0F3CA12146CBF886B60103AEC21A5CFAA268

Bitcoin forum上讨论此事时,有人提到获得该中间哈希可能存在一些问题。

如何在Google Go中计算中间状态SHA-256哈希?

4 个答案:

答案 0 :(得分:5)

比特币相关的字节操作有点棘手,因为它们倾向于随心所欲地切换字节序。首先,我们采用表示

的初始[]字节数组
00000001c570c4764aadb3f09895619f549000b8b51a789e7f58ea750000709700000000103ca064f8c76c390683f8203043e91466a7fcc40e6ebc428fbcc2d89b574a864db8345b1b00b5ac00000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000

然后,我们将数组的前半部分分开,获得:

00000001c570c4764aadb3f09895619f549000b8b51a789e7f58ea750000709700000000103ca06 4f8c76c390683f8203043e91466a7fcc40e6ebc428fbcc2d8

之后,我们需要交换一些字节。我们在每个4字节的片中反转字节顺序,从而获得:

0100000076C470C5F0B3AD4A9F619598B80090549E781AB575EA587F977000000000000064A03C10396CC7F820F8830614E94330C4FCA76642BC6E0ED8C2BC8F

这就是我们将用于计算中间状态的数组。现在,我们需要更改文件hash.go,添加到type Hash interface

Midstate() []byte

并更改文件sha256.go,添加此功能:

func (d *digest) Midstate() []byte {
    var answer []byte
    for i:=0;i<len(d.h);i++{
        answer=append(answer[:], Uint322Hex(d.h[i])...)
    }
    return answer
}

Uint322Hexuint32变量转换为[]byte变量的位置。完成所有这些后,我们可以致电:

var h BitSHA.Hash = BitSHA.New()
h.Write(Str2Hex("0100000076C470C5F0B3AD4A9F619598B80090549E781AB575EA587F977000000000000064A03C10396CC7F820F8830614E94330C4FCA76642BC6E0ED8C2BC8F"))
log.Printf("%X", h.Midstate())

Str2Hexstring变为[]byte的位置。结果是:

69FC72E76DB0E764615A858F483E3566E42D56B2BC7A03ADCE9492887010EDA8

记住正确答案:

e772fc6964e7b06d8f855a6166353e48b2562de4ad037abc889294cea8ed1070

我们可以比较它们:

69FC72E7 6DB0E764 615A858F 483E3566 E42D56B2 BC7A03AD CE949288 7010EDA8
e772fc69 64e7b06d 8f855a61 66353e48 b2562de4 ad037abc 889294ce a8ed1070

所以我们可以看到,我们只需要在每个4字节的片中交换一个字节,我们就会有比特币池和矿工使用的正确的“中间状态”(直到它不再需要建议使用)。

答案 1 :(得分:3)

您拥有的Go代码是计算字节流sha256的正确方法。

最有可能的答案是你想要做的不是sha256。具体做法是:

  

必须将它分成两个64位数据并在将结果一起散列之前单独散列它们。如果要经常更改数据后半部分的某些位,可以简化计算并仅对数据的前半部分进行一次哈希。

不是计算sha256的有效方法(读http://doc.golang.org/src/pkg/crypto/sha256/sha256.go,例如,看到sha256对数据块起作用,必须填充等等)。

您描述的算法会计算某些内容,但不会计算sha256。

由于您知道预期值,因此您可能会在另一种语言中使用您的算法进行一些参考实现,因此只需逐行执行Go。

最后,无论如何,这都是一个可疑的优化。 128位是16个字节。散列成本通常与数据大小成正比。在16字节时,成本非常小,以至于通过分割8字节部分中的数据来试图变得聪明的额外工作可能比您节省的成本更高。

答案 2 :(得分:2)

sha256.go中,在函数Sum()的开头,实现正在复制SHA256状态。 SHA256(struct digest)的基础数据类型是sha256包的私有。

我建议您自己创建sha256.go文件的私有副本(它是一个小文件)。然后添加Copy()函数以保存摘要的当前状态:

func (d *digest) Copy() hash.Hash {
    d_copy := *d
    return &d_copy
}

然后只需调用Copy()函数来保存中间状态SHA256哈希。

答案 3 :(得分:0)

我使用Intel i5 2.70 GHz CPU在128字节数据上运行了两个Go基准测试。首先,1000次,我将所有128个字节写入SHA256哈希并读取总和,总共花费了大约9,285,000纳秒。其次,我将前64个字节写入SHA256哈希,然后1000次,我将第二个64字节写入SHA256哈希的副本并读取总和,总共花费了大约6,492,371纳秒。第二个基准测试假设前64个字节是不变的,比第一个基准测试的时间减少了30%。

使用第一种方法,您可以在购买更快的CPU之前每天计算大约9,305,331,179个SHA256 128字节的总和。使用第二种方法,您可以计算每天13,307,927,103个SHA256 128字节和,假设前64个字节连续1000次不变,然后购买更快的CPU。您需要计算每天多少SHA256 128字节的总和?对于每天有多少SHA256 128字节和,前64个字节是不变的吗?

您运行了哪些基准测试?结果是什么?