-
Notifications
You must be signed in to change notification settings - Fork 6
/
sip13.go
83 lines (72 loc) · 1.64 KB
/
sip13.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// +build !amd64 noasm
package sip13
import (
"math/bits"
"unsafe"
)
func Sum64(k0, k1 uint64, b []byte) uint64 {
return Sum64Str(k0, k1, unsafeB2S(b))
}
func readUint64(b string) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}
func unsafeB2S(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func Sum64Str(k0, k1 uint64, p string) uint64 {
var v0, v1, v2, v3 uint64
v0 = k0 ^ 0x736f6d6570736575
v1 = k1 ^ 0x646f72616e646f6d
v2 = k0 ^ 0x6c7967656e657261
v3 = k1 ^ 0x7465646279746573
b := uint64(len(p)) << 56
for len(p) >= 8 {
m := readUint64(p)
v3 ^= m
v0 += v1
v2 += v3
v1 = bits.RotateLeft64(v1, 13)
v3 = bits.RotateLeft64(v3, 16)
v1 ^= v0
v3 ^= v2
v0 = bits.RotateLeft64(v0, 32)
v2 += v1
v0 += v3
v1 = bits.RotateLeft64(v1, 17)
v3 = bits.RotateLeft64(v3, 21)
v1 ^= v2
v3 ^= v0
v2 = bits.RotateLeft64(v2, 32)
v0 ^= m
p = p[8:]
}
for _, c := range []byte(p) {
b = bits.RotateLeft64(b|uint64(c), 56)
}
m := bits.RotateLeft64(b, len(p)*8)
// last block with finalization
v3 ^= m
f := uint64(0xff)
for i := 0; i < 4; i++ {
v0 += v1
v2 += v3
v1 = bits.RotateLeft64(v1, 13)
v3 = bits.RotateLeft64(v3, 16)
v1 ^= v0
v3 ^= v2
v0 = bits.RotateLeft64(v0, 32)
v2 += v1
v0 += v3
v1 = bits.RotateLeft64(v1, 17)
v3 = bits.RotateLeft64(v3, 21)
v1 ^= v2
v3 ^= v0
v2 = bits.RotateLeft64(v2, 32)
v2 ^= f
v0 ^= m
m, f = 0, 0 // clear last block and finalization mixins
}
return v0 ^ v1 ^ v2 ^ v3
}