From fde06c7514b009ff955ca0ed5b52c219a91e89d3 Mon Sep 17 00:00:00 2001 From: Tarak Ben Youssef Date: Sat, 22 Apr 2023 00:48:40 -0600 Subject: [PATCH 1/2] remove DKG simulation and fastKG flag --- cmd/bootstrap/cmd/dkg.go | 8 +- cmd/bootstrap/cmd/finalize_test.go | 7 - cmd/bootstrap/cmd/rootblock.go | 8 +- cmd/bootstrap/cmd/rootblock_test.go | 4 - cmd/bootstrap/dkg/dkg.go | 201 +--------------------------- cmd/bootstrap/dkg/dkg_test.go | 17 ++- 6 files changed, 19 insertions(+), 226 deletions(-) diff --git a/cmd/bootstrap/cmd/dkg.go b/cmd/bootstrap/cmd/dkg.go index b190b1a7c2c..d7069534e64 100644 --- a/cmd/bootstrap/cmd/dkg.go +++ b/cmd/bootstrap/cmd/dkg.go @@ -11,7 +11,7 @@ import ( "github.com/onflow/flow-go/state/protocol/inmem" ) -func runDKG(nodes []model.NodeInfo) dkg.DKGData { +func runBeaconKG(nodes []model.NodeInfo) dkg.DKGData { n := len(nodes) log.Info().Msgf("read %v node infos for DKG", n) @@ -19,11 +19,7 @@ func runDKG(nodes []model.NodeInfo) dkg.DKGData { log.Debug().Msgf("will run DKG") var dkgData dkg.DKGData var err error - if flagFastKG { - dkgData, err = bootstrapDKG.RunFastKG(n, flagBootstrapRandomSeed) - } else { - dkgData, err = bootstrapDKG.RunDKG(n, GenerateRandomSeeds(n, crypto.SeedMinLenDKG)) - } + dkgData, err = bootstrapDKG.RandomBeaconKG(n, GenerateRandomSeed(crypto.SeedMinLenDKG)) if err != nil { log.Fatal().Err(err).Msg("error running DKG") } diff --git a/cmd/bootstrap/cmd/finalize_test.go b/cmd/bootstrap/cmd/finalize_test.go index 033e29b6609..816760540da 100644 --- a/cmd/bootstrap/cmd/finalize_test.go +++ b/cmd/bootstrap/cmd/finalize_test.go @@ -68,7 +68,6 @@ func TestFinalize_HappyPath(t *testing.T) { flagPartnerWeights = partnerWeights flagInternalNodePrivInfoDir = internalPrivDir - flagFastKG = true flagRootChain = chainName flagRootParent = hex.EncodeToString(rootParent[:]) flagRootHeight = rootHeight @@ -119,8 +118,6 @@ func TestFinalize_Deterministic(t *testing.T) { flagPartnerWeights = partnerWeights flagInternalNodePrivInfoDir = internalPrivDir - flagFastKG = true - flagRootCommit = hex.EncodeToString(rootCommit[:]) flagRootParent = hex.EncodeToString(rootParent[:]) flagRootChain = chainName @@ -198,8 +195,6 @@ func TestFinalize_SameSeedDifferentStateCommits(t *testing.T) { flagPartnerWeights = partnerWeights flagInternalNodePrivInfoDir = internalPrivDir - flagFastKG = true - flagRootCommit = hex.EncodeToString(rootCommit[:]) flagRootParent = hex.EncodeToString(rootParent[:]) flagRootChain = chainName @@ -308,8 +303,6 @@ func TestFinalize_InvalidRandomSeedLength(t *testing.T) { flagPartnerWeights = partnerWeights flagInternalNodePrivInfoDir = internalPrivDir - flagFastKG = true - flagRootCommit = hex.EncodeToString(rootCommit[:]) flagRootParent = hex.EncodeToString(rootParent[:]) flagRootChain = chainName diff --git a/cmd/bootstrap/cmd/rootblock.go b/cmd/bootstrap/cmd/rootblock.go index d9acfff8037..dd530f562d6 100644 --- a/cmd/bootstrap/cmd/rootblock.go +++ b/cmd/bootstrap/cmd/rootblock.go @@ -12,7 +12,6 @@ import ( ) var ( - flagFastKG bool flagRootChain string flagRootParent string flagRootHeight uint64 @@ -23,7 +22,7 @@ var ( var rootBlockCmd = &cobra.Command{ Use: "rootblock", Short: "Generate root block data", - Long: `Run DKG, generate root block and votes for root block needed for constructing QC. Serialize all info into file`, + Long: `Run Beacon KeyGen, generate root block and votes for root block needed for constructing QC. Serialize all info into file`, Run: rootBlock, } @@ -61,9 +60,6 @@ func addRootBlockCmdFlags() { cmd.MarkFlagRequired(rootBlockCmd, "root-height") rootBlockCmd.Flags().BytesHexVar(&flagBootstrapRandomSeed, "random-seed", GenerateRandomSeed(flow.EpochSetupRandomSourceLength), "The seed used to for DKG, Clustering and Cluster QC generation") - - // optional parameters to influence various aspects of identity generation - rootBlockCmd.Flags().BoolVar(&flagFastKG, "fast-kg", false, "use fast (centralized) random beacon key generation instead of DKG") } func rootBlock(cmd *cobra.Command, args []string) { @@ -104,7 +100,7 @@ func rootBlock(cmd *cobra.Command, args []string) { log.Info().Msg("") log.Info().Msg("running DKG for consensus nodes") - dkgData := runDKG(model.FilterByRole(stakingNodes, flow.RoleConsensus)) + dkgData := runBeaconKG(model.FilterByRole(stakingNodes, flow.RoleConsensus)) log.Info().Msg("") log.Info().Msg("constructing root block") diff --git a/cmd/bootstrap/cmd/rootblock_test.go b/cmd/bootstrap/cmd/rootblock_test.go index 0883037115f..09bc7d10305 100644 --- a/cmd/bootstrap/cmd/rootblock_test.go +++ b/cmd/bootstrap/cmd/rootblock_test.go @@ -56,8 +56,6 @@ func TestRootBlock_HappyPath(t *testing.T) { flagPartnerWeights = partnerWeights flagInternalNodePrivInfoDir = internalPrivDir - flagFastKG = true - flagRootParent = hex.EncodeToString(rootParent[:]) flagRootChain = chainName flagRootHeight = rootHeight @@ -93,8 +91,6 @@ func TestRootBlock_Deterministic(t *testing.T) { flagPartnerWeights = partnerWeights flagInternalNodePrivInfoDir = internalPrivDir - flagFastKG = true - flagRootParent = hex.EncodeToString(rootParent[:]) flagRootChain = chainName flagRootHeight = rootHeight diff --git a/cmd/bootstrap/dkg/dkg.go b/cmd/bootstrap/dkg/dkg.go index b519c59829b..3b65f44964a 100644 --- a/cmd/bootstrap/dkg/dkg.go +++ b/cmd/bootstrap/dkg/dkg.go @@ -2,210 +2,19 @@ package dkg import ( "fmt" - "sync" - "time" - - "github.com/rs/zerolog/log" "github.com/onflow/flow-go/crypto" model "github.com/onflow/flow-go/model/dkg" "github.com/onflow/flow-go/module/signature" ) -// RunDKG simulates a distributed DKG protocol by running the protocol locally -// and generating the DKG output info -func RunDKG(n int, seeds [][]byte) (model.DKGData, error) { - - if n != len(seeds) { - return model.DKGData{}, fmt.Errorf("n needs to match the number of seeds (%v != %v)", n, len(seeds)) - } - - // separate the case whith one node - if n == 1 { - sk, pk, pkGroup, err := thresholdSignKeyGenOneNode(seeds[0]) - if err != nil { - return model.DKGData{}, fmt.Errorf("run dkg failed: %w", err) - } - - dkgData := model.DKGData{ - PrivKeyShares: sk, - PubGroupKey: pkGroup, - PubKeyShares: pk, - } - - return dkgData, nil - } - - processors := make([]localDKGProcessor, 0, n) - - // create the message channels for node communication - chans := make([]chan *message, n) - for i := 0; i < n; i++ { - chans[i] = make(chan *message, 5*n) - } - - // create processors for all nodes - for i := 0; i < n; i++ { - processors = append(processors, localDKGProcessor{ - current: i, - chans: chans, - }) - } - - // create DKG instances for all nodes - for i := 0; i < n; i++ { - var err error - processors[i].dkg, err = crypto.NewJointFeldman(n, - signature.RandomBeaconThreshold(n), i, &processors[i]) - if err != nil { - return model.DKGData{}, err - } - } - - var wg sync.WaitGroup - phase := 0 - - // start DKG in all nodes - // start listening on the channels - wg.Add(n) - for i := 0; i < n; i++ { - // start dkg could also run in parallel - // but they are run sequentially to avoid having non-deterministic - // output (the PRG used is common) - err := processors[i].dkg.Start(seeds[i]) - if err != nil { - return model.DKGData{}, err - } - go dkgRunChan(&processors[i], &wg, phase) - } - phase++ - - // sync the two timeouts and start the next phase - for ; phase <= 2; phase++ { - wg.Wait() - wg.Add(n) - for i := 0; i < n; i++ { - go dkgRunChan(&processors[i], &wg, phase) - } - } - - // synchronize the main thread to end all DKGs - wg.Wait() - - skShares := make([]crypto.PrivateKey, 0, n) - - for _, processor := range processors { - skShares = append(skShares, processor.privkey) - } - - dkgData := model.DKGData{ - PrivKeyShares: skShares, - PubGroupKey: processors[0].pubgroupkey, - PubKeyShares: processors[0].pubkeys, - } - - return dkgData, nil -} - -// localDKGProcessor implements DKGProcessor interface -type localDKGProcessor struct { - current int - dkg crypto.DKGState - chans []chan *message - privkey crypto.PrivateKey - pubgroupkey crypto.PublicKey - pubkeys []crypto.PublicKey -} - -const ( - broadcast int = iota - private -) - -type message struct { - orig int - channel int - data []byte -} - -// PrivateSend sends a message from one node to another -func (proc *localDKGProcessor) PrivateSend(dest int, data []byte) { - newMsg := &message{proc.current, private, data} - proc.chans[dest] <- newMsg -} - -// Broadcast a message from one node to all nodes -func (proc *localDKGProcessor) Broadcast(data []byte) { - newMsg := &message{proc.current, broadcast, data} - for i := 0; i < len(proc.chans); i++ { - if i != proc.current { - proc.chans[i] <- newMsg - } - } -} - -// Disqualify a node -func (proc *localDKGProcessor) Disqualify(node int, log string) { -} - -// FlagMisbehavior flags a node for misbehaviour -func (proc *localDKGProcessor) FlagMisbehavior(node int, log string) { -} - -// dkgRunChan simulates processing incoming messages by a node -// it assumes proc.dkg is already running -func dkgRunChan(proc *localDKGProcessor, sync *sync.WaitGroup, phase int) { - for { - select { - case newMsg := <-proc.chans[proc.current]: - var err error - if newMsg.channel == private { - err = proc.dkg.HandlePrivateMsg(newMsg.orig, newMsg.data) - } else { - err = proc.dkg.HandleBroadcastMsg(newMsg.orig, newMsg.data) - } - if err != nil { - log.Fatal().Err(err).Msg("failed to receive DKG mst") - } - // if timeout, stop and finalize - case <-time.After(1 * time.Second): - switch phase { - case 0: - err := proc.dkg.NextTimeout() - if err != nil { - log.Fatal().Err(err).Msg("failed to wait for next timeout") - } - case 1: - err := proc.dkg.NextTimeout() - if err != nil { - log.Fatal().Err(err).Msg("failed to wait for next timeout") - } - case 2: - privkey, pubgroupkey, pubkeys, err := proc.dkg.End() - if err != nil { - log.Fatal().Err(err).Msg("end dkg error should be nit") - } - if privkey == nil { - log.Fatal().Msg("privkey was nil") - } - - proc.privkey = privkey - proc.pubgroupkey = pubgroupkey - proc.pubkeys = pubkeys - } - sync.Done() - return - } - } -} - -// RunFastKG is an alternative to RunDKG that runs much faster by using a centralized threshold signature key generation. -func RunFastKG(n int, seed []byte) (model.DKGData, error) { +// RandomBeaconKG is centralized BLS threshold signature key generation. +func RandomBeaconKG(n int, seed []byte) (model.DKGData, error) { if n == 1 { sk, pk, pkGroup, err := thresholdSignKeyGenOneNode(seed) if err != nil { - return model.DKGData{}, fmt.Errorf("fast KeyGen failed: %w", err) + return model.DKGData{}, fmt.Errorf("Beacon KeyGen failed: %w", err) } dkgData := model.DKGData{ @@ -219,7 +28,7 @@ func RunFastKG(n int, seed []byte) (model.DKGData, error) { skShares, pkShares, pkGroup, err := crypto.BLSThresholdKeyGen(int(n), signature.RandomBeaconThreshold(int(n)), seed) if err != nil { - return model.DKGData{}, fmt.Errorf("fast KeyGen failed: %w", err) + return model.DKGData{}, fmt.Errorf("Beacon KeyGen failed: %w", err) } dkgData := model.DKGData{ @@ -231,7 +40,7 @@ func RunFastKG(n int, seed []byte) (model.DKGData, error) { return dkgData, nil } -// simulates DKG with one single node +// Beacon KG with one node func thresholdSignKeyGenOneNode(seed []byte) ([]crypto.PrivateKey, []crypto.PublicKey, crypto.PublicKey, error) { sk, err := crypto.GeneratePrivateKey(crypto.BLSBLS12381, seed) if err != nil { diff --git a/cmd/bootstrap/dkg/dkg_test.go b/cmd/bootstrap/dkg/dkg_test.go index 9835cdca538..a5d5a56de18 100644 --- a/cmd/bootstrap/dkg/dkg_test.go +++ b/cmd/bootstrap/dkg/dkg_test.go @@ -9,17 +9,20 @@ import ( "github.com/onflow/flow-go/utils/unittest" ) -func TestRunDKG(t *testing.T) { - seedLen := crypto.SeedMinLenDKG - _, err := RunDKG(0, unittest.SeedFixtures(2, seedLen)) - require.EqualError(t, err, "n needs to match the number of seeds (0 != 2)") +func TestBeaconKG(t *testing.T) { + seed := unittest.SeedFixture(2 * crypto.SeedMinLenDKG) - _, err = RunDKG(3, unittest.SeedFixtures(2, seedLen)) - require.EqualError(t, err, "n needs to match the number of seeds (3 != 2)") + // n = 0 + _, err := RandomBeaconKG(0, seed) + require.EqualError(t, err, "Beacon KeyGen failed: size should be between 2 and 254, got 0") - data, err := RunDKG(4, unittest.SeedFixtures(4, seedLen)) + // should work for case n = 1 + _, err = RandomBeaconKG(1, seed) require.NoError(t, err) + // n = 4 + data, err := RandomBeaconKG(4, seed) + require.NoError(t, err) require.Len(t, data.PrivKeyShares, 4) require.Len(t, data.PubKeyShares, 4) } From 0285e8ab7e9b2cfaf7be9f21804deb25e4339622 Mon Sep 17 00:00:00 2001 From: Tarak Ben Youssef Date: Sat, 22 Apr 2023 00:49:01 -0600 Subject: [PATCH 2/2] update RB Keygen call --- .../hotstuff/votecollector/combined_vote_processor_v2_test.go | 2 +- .../hotstuff/votecollector/combined_vote_processor_v3_test.go | 2 +- consensus/integration/nodes_test.go | 2 +- integration/testnet/network.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/hotstuff/votecollector/combined_vote_processor_v2_test.go b/consensus/hotstuff/votecollector/combined_vote_processor_v2_test.go index ef1fa25df85..63ee234d68a 100644 --- a/consensus/hotstuff/votecollector/combined_vote_processor_v2_test.go +++ b/consensus/hotstuff/votecollector/combined_vote_processor_v2_test.go @@ -789,7 +789,7 @@ func TestCombinedVoteProcessorV2_BuildVerifyQC(t *testing.T) { epochLookup.On("EpochForViewWithFallback", view).Return(epochCounter, nil) // all committee members run DKG - dkgData, err := bootstrapDKG.RunFastKG(11, unittest.RandomBytes(32)) + dkgData, err := bootstrapDKG.RandomBeaconKG(11, unittest.RandomBytes(32)) require.NoError(t, err) // signers hold objects that are created with private key and can sign votes and proposals diff --git a/consensus/hotstuff/votecollector/combined_vote_processor_v3_test.go b/consensus/hotstuff/votecollector/combined_vote_processor_v3_test.go index 01497d59ff5..e3d370dfb4f 100644 --- a/consensus/hotstuff/votecollector/combined_vote_processor_v3_test.go +++ b/consensus/hotstuff/votecollector/combined_vote_processor_v3_test.go @@ -924,7 +924,7 @@ func TestCombinedVoteProcessorV3_BuildVerifyQC(t *testing.T) { view := uint64(20) epochLookup.On("EpochForViewWithFallback", view).Return(epochCounter, nil) - dkgData, err := bootstrapDKG.RunFastKG(11, unittest.RandomBytes(32)) + dkgData, err := bootstrapDKG.RandomBeaconKG(11, unittest.RandomBytes(32)) require.NoError(t, err) // signers hold objects that are created with private key and can sign votes and proposals diff --git a/consensus/integration/nodes_test.go b/consensus/integration/nodes_test.go index b24b5b16ee4..837c1301fda 100644 --- a/consensus/integration/nodes_test.go +++ b/consensus/integration/nodes_test.go @@ -314,7 +314,7 @@ func createConsensusIdentities(t *testing.T, n int) *run.ParticipantData { // completeConsensusIdentities runs KG process and fills nodeInfos with missing random beacon keys func completeConsensusIdentities(t *testing.T, nodeInfos []bootstrap.NodeInfo) *run.ParticipantData { - dkgData, err := bootstrapDKG.RunFastKG(len(nodeInfos), unittest.RandomBytes(48)) + dkgData, err := bootstrapDKG.RandomBeaconKG(len(nodeInfos), unittest.RandomBytes(48)) require.NoError(t, err) participantData := &run.ParticipantData{ diff --git a/integration/testnet/network.go b/integration/testnet/network.go index 8c797838164..1520725b335 100644 --- a/integration/testnet/network.go +++ b/integration/testnet/network.go @@ -1231,7 +1231,7 @@ func runBeaconKG(confs []ContainerConfig) (dkgmod.DKGData, error) { return dkgmod.DKGData{}, err } - dkg, err := dkg.RunFastKG(nConsensusNodes, dkgSeed) + dkg, err := dkg.RandomBeaconKG(nConsensusNodes, dkgSeed) if err != nil { return dkgmod.DKGData{}, err }