Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QSP-6: Enforces crypto-secure PRNGs #6401

Merged
merged 22 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ nogo(
"@org_golang_x_tools//go/analysis/passes/asmdecl:go_tool_library",
"//tools/analyzers/maligned:go_tool_library",
"//tools/analyzers/roughtime:go_tool_library",
"//tools/analyzers/cryptorand:go_tool_library",
"//tools/analyzers/errcheck:go_tool_library",
"//tools/analyzers/featureconfig:go_tool_library",
] + select({
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/db/testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ go_library(
"//beacon-chain/cache:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/kv:go_default_library",
"//shared/rand:go_default_library",
"//shared/testutil:go_default_library",
],
)
8 changes: 2 additions & 6 deletions beacon-chain/db/testing/setup_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,21 @@
package testing

import (
"crypto/rand"
"fmt"
"math/big"
"os"
"path"
"testing"

"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/db/kv"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/testutil"
)

// SetupDB instantiates and returns database backed by key value store.
func SetupDB(t testing.TB) (db.Database, *cache.StateSummaryCache) {
randPath, err := rand.Int(rand.Reader, big.NewInt(1000000))
if err != nil {
t.Fatalf("could not generate random file path: %v", err)
}
randPath := rand.NewDeterministicGenerator().Int()
p := path.Join(testutil.TempDir(), fmt.Sprintf("/%d", randPath))
if err := os.RemoveAll(p); err != nil {
t.Fatalf("failed to remove directory: %v", err)
Expand Down
3 changes: 0 additions & 3 deletions beacon-chain/rpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ package rpc
import (
"context"
"fmt"
"math/rand"
"net"
"os"

middleware "github.com/grpc-ecosystem/go-grpc-middleware"
recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
Expand Down Expand Up @@ -50,7 +48,6 @@ var log logrus.FieldLogger

func init() {
log = logrus.WithField("prefix", "rpc")
rand.Seed(int64(os.Getpid()))
}

// Service defining an RPC server for a beacon node.
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/rpc/validator/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ go_library(
"//shared/featureconfig:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
"//shared/rand:go_default_library",
"//shared/roughtime:go_default_library",
"//shared/slotutil:go_default_library",
"//shared/traceutil:go_default_library",
Expand Down
35 changes: 11 additions & 24 deletions beacon-chain/rpc/validator/assignments.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ package validator

import (
"context"
"crypto/rand"
"math/big"
"time"

"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
Expand All @@ -15,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/roughtime"
"github.com/prysmaticlabs/prysm/shared/slotutil"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -178,12 +176,8 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
validatorAssignments = append(validatorAssignments, assignment)
nextValidatorAssignments = append(nextValidatorAssignments, nextAssignment)
// Assign relevant validator to subnet.
if err := assignValidatorToSubnet(pubKey, assignment.Status); err != nil {
return nil, errors.Wrap(err, "could not assign validator to subnet")
}
if err := assignValidatorToSubnet(pubKey, nextAssignment.Status); err != nil {
return nil, errors.Wrap(err, "could not assign validator to subnet")
}
assignValidatorToSubnet(pubKey, assignment.Status)
assignValidatorToSubnet(pubKey, nextAssignment.Status)
}

return &ethpb.DutiesResponse{
Expand All @@ -195,33 +189,26 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.

// assignValidatorToSubnet checks the status and pubkey of a particular validator
// to discern whether persistent subnets need to be registered for them.
func assignValidatorToSubnet(pubkey []byte, status ethpb.ValidatorStatus) error {
func assignValidatorToSubnet(pubkey []byte, status ethpb.ValidatorStatus) {
if status != ethpb.ValidatorStatus_ACTIVE && status != ethpb.ValidatorStatus_EXITING {
return nil
return
}

_, ok, expTime := cache.SubnetIDs.GetPersistentSubnets(pubkey)
if ok && expTime.After(roughtime.Now()) {
return nil
return
}
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot)
assignedIdxs := []uint64{}
randGen := rand.NewGenerator()
for i := uint64(0); i < params.BeaconNetworkConfig().RandomSubnetsPerValidator; i++ {
randInt, err := rand.Int(rand.Reader, big.NewInt(int64(params.BeaconNetworkConfig().AttestationSubnetCount)))
if err != nil {
return errors.Wrap(err, "could not get random subnet index")
}
assignedIdxs = append(assignedIdxs, randInt.Uint64())
assignedIdx := randGen.Intn(int(params.BeaconNetworkConfig().AttestationSubnetCount))
assignedIdxs = append(assignedIdxs, uint64(assignedIdx))
}

randInt, err := rand.Int(rand.Reader, big.NewInt(int64(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)))
if err != nil {
return errors.Wrap(err, "could not get random subnet duration")
}
assignedDuration := randInt.Int64()
assignedDuration += int64(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)
assignedDuration := randGen.Intn(int(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription))
assignedDuration += int(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)

totalDuration := epochDuration * time.Duration(assignedDuration)
cache.SubnetIDs.AddPersistentCommittee(pubkey, assignedIdxs, totalDuration*time.Second)
return nil
}
4 changes: 1 addition & 3 deletions beacon-chain/rpc/validator/assignments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,9 +467,7 @@ func TestStreamDuties_OK_ChainReorg(t *testing.T) {
func TestAssignValidatorToSubnet(t *testing.T) {
k := pubKey(3)

if err := assignValidatorToSubnet(k, ethpb.ValidatorStatus_ACTIVE); err != nil {
t.Fatal(err)
}
assignValidatorToSubnet(k, ethpb.ValidatorStatus_ACTIVE)
coms, ok, exp := cache.SubnetIDs.GetPersistentSubnets(k)
if !ok {
t.Fatal("No cache entry found for validator")
Expand Down
17 changes: 4 additions & 13 deletions beacon-chain/rpc/validator/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package validator

import (
"context"
"crypto/rand"
"fmt"
"math/big"
"time"
Expand All @@ -23,6 +22,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/trieutil"
"go.opencensus.io/trace"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -223,18 +223,9 @@ func (vs *Server) randomETH1DataVote(ctx context.Context) (*ethpb.Eth1Data, erro
}
// set random roots and block hashes to prevent a majority from being
// built if the eth1 node is offline
randomDepBytes := make([]byte, 32)
randomBlkBytes := make([]byte, 32)
_, err = rand.Read(randomDepBytes)
if err != nil {
return nil, err
}
_, err = rand.Read(randomBlkBytes)
if err != nil {
return nil, err
}
depRoot := hashutil.Hash(randomDepBytes)
blockHash := hashutil.Hash(randomBlkBytes)
randGen := rand.NewGenerator()
depRoot := hashutil.Hash(bytesutil.Bytes32(randGen.Uint64()))
blockHash := hashutil.Hash(bytesutil.Bytes32(randGen.Uint64()))
return &ethpb.Eth1Data{
DepositRoot: depRoot[:],
DepositCount: headState.Eth1DepositIndex(),
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/sync/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ go_library(
"//shared/messagehandler:go_default_library",
"//shared/p2putils:go_default_library",
"//shared/params:go_default_library",
"//shared/rand:go_default_library",
"//shared/roughtime:go_default_library",
"//shared/runutil:go_default_library",
"//shared/sliceutil:go_default_library",
Expand All @@ -88,7 +89,6 @@ go_library(
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_x_exp//rand:go_default_library",
],
)

Expand Down
1 change: 1 addition & 0 deletions beacon-chain/sync/initial-sync/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ go_library(
"//shared/bytesutil:go_default_library",
"//shared/mathutil:go_default_library",
"//shared/params:go_default_library",
"//shared/rand:go_default_library",
"//shared/roughtime:go_default_library",
"@com_github_kevinms_leakybucket_go//:go_default_library",
"@com_github_libp2p_go_libp2p_core//peer:go_default_library",
Expand Down
26 changes: 6 additions & 20 deletions beacon-chain/sync/initial-sync/blocks_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package initialsync

import (
"context"
"crypto/rand"
"fmt"
"io"
"math"
"math/big"
mathRand "math/rand"
"sort"
"sync"
"time"
Expand All @@ -24,6 +21,7 @@ import (
p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/mathutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/roughtime"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
Expand Down Expand Up @@ -64,6 +62,7 @@ type blocksFetcher struct {
sync.Mutex
ctx context.Context
cancel context.CancelFunc
rand *rand.Rand
headFetcher blockchain.HeadFetcher
p2p p2p.P2P
blocksPerSecond uint64
Expand Down Expand Up @@ -108,6 +107,7 @@ func newBlocksFetcher(ctx context.Context, cfg *blocksFetcherConfig) *blocksFetc
return &blocksFetcher{
ctx: ctx,
cancel: cancel,
rand: rand.NewGenerator(),
headFetcher: cfg.headFetcher,
p2p: cfg.p2p,
blocksPerSecond: uint64(blocksPerSecond),
Expand Down Expand Up @@ -387,11 +387,7 @@ func (f *blocksFetcher) selectFailOverPeer(excludedPID peer.ID, peers []peer.ID)
return "", errNoPeersAvailable
}

randInt, err := rand.Int(rand.Reader, big.NewInt(int64(len(peers))))
if err != nil {
return "", err
}
return peers[randInt.Int64()], nil
return peers[f.rand.Int()%len(peers)], nil
}

// waitForMinimumPeers spins and waits up until enough peers are available.
Expand Down Expand Up @@ -425,12 +421,7 @@ func (f *blocksFetcher) filterPeers(peers []peer.ID, peersPercentage float64) ([

// Shuffle peers to prevent a bad peer from
// stalling sync with invalid blocks.
randSource, err := rand.Int(rand.Reader, big.NewInt(roughtime.Now().Unix()))
if err != nil {
return nil, errors.Wrap(err, "could not generate random int")
}
randGenerator := mathRand.New(mathRand.NewSource(randSource.Int64()))
randGenerator.Shuffle(len(peers), func(i, j int) {
f.rand.Shuffle(len(peers), func(i, j int) {
peers[i], peers[j] = peers[j], peers[i]
})

Expand Down Expand Up @@ -478,11 +469,6 @@ func (f *blocksFetcher) nonSkippedSlotAfter(ctx context.Context, slot uint64) (u
return 0, errNoPeersAvailable
}

randSource, err := rand.Int(rand.Reader, big.NewInt(roughtime.Now().Unix()))
if err != nil {
return 0, errors.Wrap(err, "could not generate random int")
}
randGenerator := mathRand.New(mathRand.NewSource(randSource.Int64()))
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
pidInd := 0

Expand Down Expand Up @@ -525,7 +511,7 @@ func (f *blocksFetcher) nonSkippedSlotAfter(ctx context.Context, slot uint64) (u
slot = slot + nonSkippedSlotsFullSearchEpochs*slotsPerEpoch
upperBoundSlot := helpers.StartSlot(epoch + 1)
for ind := slot + 1; ind < upperBoundSlot; ind += (slotsPerEpoch * slotsPerEpoch) / 2 {
start := ind + uint64(randGenerator.Intn(int(slotsPerEpoch)))
start := ind + uint64(f.rand.Intn(int(slotsPerEpoch)))
nextSlot, err := fetch(peers[pidInd%len(peers)], start, slotsPerEpoch/2, slotsPerEpoch)
if err != nil {
return 0, err
Expand Down
5 changes: 3 additions & 2 deletions beacon-chain/sync/pending_attestations_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import (
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/runutil"
"github.com/prysmaticlabs/prysm/shared/slotutil"
"github.com/prysmaticlabs/prysm/shared/traceutil"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
"golang.org/x/exp/rand"
)

// This defines how often a node cleans up and processes pending attestations in the queue.
Expand Down Expand Up @@ -60,6 +60,7 @@ func (s *Service) processPendingAtts(ctx context.Context) error {
}
s.pendingAttsLock.RUnlock()

randGen := rand.NewGenerator()
for _, bRoot := range roots {
s.pendingAttsLock.RLock()
attestations := s.blkRootToPendingAtts[bRoot]
Expand Down Expand Up @@ -130,7 +131,7 @@ func (s *Service) processPendingAtts(ctx context.Context) error {
log.Debug("No peer IDs available to request missing block from for pending attestation")
return nil
}
pid := pids[rand.Int()%len(pids)]
pid := pids[randGen.Int()%len(pids)]
targetSlot := helpers.SlotToEpoch(attestations[0].Message.Aggregate.Data.Target.Epoch)
for _, p := range pids {
cs, err := s.p2p.Peers().ChainState(p)
Expand Down
5 changes: 3 additions & 2 deletions beacon-chain/sync/pending_blocks_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/runutil"
"github.com/prysmaticlabs/prysm/shared/slotutil"
"github.com/prysmaticlabs/prysm/shared/traceutil"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
"golang.org/x/exp/rand"
)

var processPendingBlocksPeriod = slotutil.DivideSlotBy(3 /* times per slot */)
Expand Down Expand Up @@ -51,6 +51,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
trace.Int64Attribute("numPeers", int64(len(pids))),
)

randGen := rand.NewGenerator()
for _, slot := range slots {
ctx, span := trace.StartSpan(ctx, "processPendingBlocks.InnerLoop")
span.AddAttributes(trace.Int64Attribute("slot", int64(slot)))
Expand Down Expand Up @@ -80,7 +81,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {

// Start with a random peer to query, but choose the first peer in our unsorted list that claims to
// have a head slot newer than the block slot we are requesting.
pid := pids[rand.Int()%len(pids)]
pid := pids[randGen.Int()%len(pids)]
for _, p := range pids {
cs, err := s.p2p.Peers().ChainState(p)
if err != nil {
Expand Down