-
Notifications
You must be signed in to change notification settings - Fork 30
/
util.go
75 lines (67 loc) · 2.05 KB
/
util.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 crypto
import (
"bytes"
"crypto/rand"
"golang.org/x/crypto/sha3"
)
const (
// HashSizeByte is the size of the hash output in bytes.
HashSizeByte = 32
// HashID identifies the used hash as a string.
HashID = "SHAKE128"
)
// Digest hashes all passed byte slices.
// The passed slices won't be mutated.
func Digest(ms ...[]byte) []byte {
h := sha3.NewShake128()
for _, m := range ms {
h.Write(m)
}
ret := make([]byte, HashSizeByte)
h.Read(ret)
return ret
}
// MakeRand returns a random slice of bytes.
// It returns an error if there was a problem while generating
// the random slice.
// It is different from the 'standard' random byte generation as it
// hashes its output before returning it; by hashing the system's
// PRNG output before it is send over the wire, we aim to make the
// random output less predictable (even if the system's PRNG isn't
// as unpredictable as desired).
// See https://trac.torproject.org/projects/tor/ticket/17694
func MakeRand() ([]byte, error) {
r := make([]byte, HashSizeByte)
if _, err := rand.Read(r); err != nil {
return nil, err
}
// Do not directly reveal bytes from rand.Read on the wire
return Digest(r), nil
}
// Commit can be used to create a cryptographic commit to some value (use
// NewCommit() for this purpose.
type Commit struct {
// Salt is a cryptographic salt which will be hashed in addition
// to the value.
Salt []byte
// Value is the actual value to commit to.
Value []byte
}
// NewCommit creates a new cryptographic commit to the passed byte slices
// stuff (which won't be mutated). It creates a random salt before
// committing to the values.
func NewCommit(stuff ...[]byte) (*Commit, error) {
salt, err := MakeRand()
if err != nil {
return nil, err
}
return &Commit{
Salt: salt,
Value: Digest(append([][]byte{salt}, stuff...)...),
}, nil
}
// Verify verifies that the underlying commit c was a commit to the passed
// byte slices stuff (which won't be mutated).
func (c *Commit) Verify(stuff ...[]byte) bool {
return bytes.Equal(c.Value, Digest(append([][]byte{c.Salt}, stuff...)...))
}