-
Notifications
You must be signed in to change notification settings - Fork 462
/
randomness.go
97 lines (83 loc) · 3.58 KB
/
randomness.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package chain
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/venus/pkg/types"
"github.com/minio/blake2b-simd"
"github.com/pkg/errors"
"math/rand"
)
type RandomSeed []byte
///// Chain sampling /////
type ChainSampler interface { //nolint
Sample(ctx context.Context, epoch abi.ChainEpoch) (RandomSeed, error)
GetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
}
// A sampler for use when computing genesis state (the state that the genesis block points to as parent state).
// There is no chain to sample a seed from.
type GenesisSampler struct {
VRFProof types.VRFPi
}
func (g *GenesisSampler) Sample(_ context.Context, epoch abi.ChainEpoch) (RandomSeed, error) {
if epoch > 0 {
return nil, fmt.Errorf("invalid use of genesis sampler for epoch %d", epoch)
}
return MakeRandomSeed(g.VRFProof)
}
func (g *GenesisSampler) GetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
//use trust beacon value todo
out := make([]byte, 32)
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint
return out, nil
}
// Computes a random seed from raw ticket bytes.
// A randomness seed is the VRF digest of the minimum ticket of the tipset at or before the requested epoch
func MakeRandomSeed(rawVRFProof types.VRFPi) (RandomSeed, error) {
digest := rawVRFProof.Digest()
return digest[:], nil
}
///// GetRandomnessFromTickets derivation /////
// RandomnessSource provides randomness to actors.
type RandomnessSource interface {
GetRandomnessFromTickets(ctx context.Context, tag crypto.DomainSeparationTag, epoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
GetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
}
// A randomness source that seeds computations with a sample drawn from a chain epoch.
type ChainRandomnessSource struct { //nolint
Sampler ChainSampler
}
func (c *ChainRandomnessSource) GetRandomnessFromTickets(ctx context.Context, tag crypto.DomainSeparationTag, epoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
seed, err := c.Sampler.Sample(ctx, epoch)
if err != nil {
return nil, errors.Wrap(err, "failed to sample chain for randomness")
}
return BlendEntropy(tag, seed, epoch, entropy)
}
func (c *ChainRandomnessSource) GetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
return c.Sampler.GetRandomnessFromBeacon(ctx, personalization, randEpoch, entropy)
}
func BlendEntropy(tag crypto.DomainSeparationTag, seed RandomSeed, epoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
buffer := bytes.Buffer{}
err := binary.Write(&buffer, binary.BigEndian, int64(tag))
if err != nil {
return nil, errors.Wrap(err, "failed to write tag for randomness")
}
_, err = buffer.Write(seed)
if err != nil {
return nil, errors.Wrap(err, "failed to write seed for randomness")
}
err = binary.Write(&buffer, binary.BigEndian, int64(epoch))
if err != nil {
return nil, errors.Wrap(err, "failed to write epoch for randomness")
}
_, err = buffer.Write(entropy)
if err != nil {
return nil, errors.Wrap(err, "failed to write entropy for randomness")
}
bufHash := blake2b.Sum256(buffer.Bytes())
return bufHash[:], nil
}