我一直在尝试在Go中实现HashCash算法!对于那些不知道的人 -
HashCash是一种阻止垃圾邮件的方法。基本上,标头由客户端和服务器都知道的一些环境变量构成(电子邮件,时间戳等)。随机的随机数附加到标题的末尾。客户端尝试通过更改nonce来强制部分哈希冲突(例如,第一个 x 位为0)。
HashCash可行,因为找到部分哈希冲突的成本并不高。当服务器收到此标头时,它们会验证其中的信息(因此它只能用于一个会话)并计算生成的哈希值。如果第一个 x 位为0,那么在客户端的机器上花费了大量时间来计算碰撞(这不会发生在spambot上)
对我来说,我只是想编写一个程序,找到客户端找到 x 位的部分哈希冲突所需的时间。
我写了这段代码,如果 int64 有 x 位的哈希冲突,它将返回true / false。
func partialAllZeroes (zeroCount uint8, val int64) (bool, os.Error) {
setBitString := "1111111111111111111111111111111111111111111111111111111111111111"
unsetBitString := "0000000000000000000000000000000000000000000000000000000000000000"
setBitString = setBitString[0:zeroCount-1]
unsetBitString = unsetBitString[0:zeroCount-1]
zeroTest, e := strconv.Btoi64(setBitString, 2) // 64 0bits
zeroes, e := strconv.Btoi64(unsetBitString, 2) // 64 1bits
if e != nil {
return false, e
}
result := val & zeroTest
switch {
case result == zeroes:
return true, nil
case result != zeroes:
return false, nil
}
return false, os.NewError("")
}
我目前的问题是我有很多类型转换问题。例如,我只能在 int64 类型上操作,因为这是 strconv.Btoi64 返回的内容。我还要看的另一个问题是哈希函数作为字节数组返回,我不知道如何将其转换为 int64 。
以下是我当前的哈希码 -
hasher := sha1.New()
baseCollisionString := "BASE COLLISION STRING"
nonce := "12345"
hasher.Write([]byte(strings.Join(baseCollisionString, nonce)))
testCollision := hasher.Sum()
// Somehow I must convert the first x bits of testCollision into an int64 type, so I can use partialAllZeroes with it
答案 0 :(得分:4)
我建议使用以下代码(函数partialAllZeroes
应该运行得更快):
package main
import "crypto/sha1"
func partialAllZeroes(zeroCount uint8, b []byte) bool {
i := 0
for zeroCount >= 8 {
if b[i] != 0 {
return false
}
i++
zeroCount -= 8
}
var mask byte
switch zeroCount {
case 0: mask = 0x00
case 1: mask = 0x01
case 2: mask = 0x03
case 3: mask = 0x07
case 4: mask = 0x0f
case 5: mask = 0x1f
case 6: mask = 0x3f
case 7: mask = 0x7f
}
return (b[i] & mask) == 0
}
func main() {
hasher := sha1.New()
baseCollisionString := "BASE COLLISION STRING"
nonce := "12345"
hasher.Write([]byte(baseCollisionString + nonce))
testCollision := hasher.Sum()
partialAllZeroes(100, testCollision)
}
答案 1 :(得分:1)
我建议使用math/big.Int类型。它可以处理大位集。它有SetString方法,它也处理二进制(如"0b101010"
)。使用fmt.Printf或Sprintf,可以使用%b
动词从中获取二进制文本字符串。
答案 2 :(得分:0)
我还建议升级到最新的每周(从昨天RC1开始)。 “go fix”命令将帮助您进行过渡。
然后使用strconv pkg:
package main
import (
"fmt"
"strconv"
"reflect"
)
func main() {
a := []byte{ '1', '1', '1', '0', '1', '0', '1', '1' }
b, err := strconv.ParseInt(string(a[:3]), 2, 64)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(b, reflect.TypeOf(b))
}