-
Notifications
You must be signed in to change notification settings - Fork 1
/
progressiveHash.go
75 lines (70 loc) · 2.28 KB
/
progressiveHash.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
package progressiveHash
import (
"errors"
"golang.org/x/crypto/blake2b"
)
// Hash - Hash `in` with seedisation `seed`, an initial number of rounds `initialRounds`,
// and increase the work factor `progressiveLength` times to eventually produce an `outLength` bit-long digest.
func Hash(in []byte, seed []byte, initialRounds uint64, progressiveLength int, outLength int) ([]byte, error) {
return hash(in, seed, initialRounds, progressiveLength, outLength, nil)
}
// Verify - Verify a previously computed hash `expected` using the input `in`, a seedisation `seed`,
// increasing the work factor `progressiveLength` times to match the initial hash length `outLength` bits.
func Verify(in []byte, seed []byte, initialRounds uint64, progressiveLength int, outLength int, expected []byte) error {
_, err := hash(in, seed, initialRounds, progressiveLength, outLength, &expected)
return err
}
func hash(in []byte, seed []byte, initialRounds uint64, progressiveLength int, outLength int, expected *[]byte) ([]byte, error) {
if progressiveLength < 0 || outLength < 1 {
return nil, errors.New("invalid output length")
}
if len(seed) > 127 {
return nil, errors.New("seed too long")
}
if outLength < progressiveLength {
outLength = progressiveLength
}
xin := make([]byte, 128+len(in))
copy(xin, seed)
copy(xin[128:], in)
h := blake2b.Sum512(xin)
var out []byte
if expected != nil {
if len(*expected) != outLength>>3 {
return out, errors.New("expected length not matching the given parameters")
}
} else {
out = make([]byte, outLength>>3)
if len(out) > len(h) {
return nil, errors.New("output too long")
}
}
xrounds := initialRounds
for i := uint(0); i < uint(progressiveLength); i++ {
for j := uint64(0); j < xrounds; j++ {
h = blake2b.Sum512(h[:])
}
if expected != nil {
if ((*expected)[i>>3]>>(i&7))&1 != uint8(h[0]&1) {
return out, errors.New("mismatch")
}
} else {
out[i>>3] |= uint8(h[0]&1) << (i & 7)
}
xrounds *= 2
}
if expected != nil {
ck := uint8(0)
for i := uint(1); i < uint(outLength); i++ {
ck |= ((*expected)[i>>3]>>(i&7))&1 ^ uint8((h[i>>3]>>(i&7))&1)
}
if ck != 0 {
return out, errors.New("mismatch")
}
} else {
for i := uint(1); i < uint(outLength); i++ {
out[i>>3] |= uint8((h[i>>3]>>(i&7))&1) << (i & 7)
}
}
return out, nil
}