// handleCommitChallenge will verify the signature + check if no more than 1/3 // of participants refused to sign. func (bft *ProtocolBFTCoSi) handleChallengeCommit(ch *ChallengeCommit) error { ch.Challenge = bft.commit.Challenge(ch.Challenge) hash := bft.Suite().Hash() hash.Write(bft.Msg) h := hash.Sum(nil) // verify if the signature is correct if err := cosi.VerifyCosiSignatureWithException(bft.suite, bft.AggregatedPublic, h, ch.Signature, ch.Exceptions); err != nil { log.Error(bft.Name(), "Verification of the signature failed:", err) bft.signRefusal = true } // Check if we have no more than 1/3 failed nodes if len(ch.Exceptions) > int(bft.threshold) { log.Errorf("More than 1/3 (%d/%d) refused to sign ! ABORT", len(ch.Exceptions), len(bft.Roster().List)) bft.signRefusal = true } // store the exceptions for later usage bft.tempExceptions = ch.Exceptions log.Lvl4("BFTCoSi handle Challenge COMMIT") if bft.IsLeaf() { return bft.startResponseCommit() } if err := bft.SendToChildrenInParallel(ch); err != nil { log.Error(err) } return nil }
func TestBftCoSi(t *testing.T) { defer log.AfterTest(t) log.TestOutput(testing.Verbose(), 4) // Register test protocol using BFTCoSi sda.ProtocolRegisterName(TestProtocolName, func(n *sda.TreeNodeInstance) (sda.ProtocolInstance, error) { return NewBFTCoSiProtocol(n, verify) }) for _, nbrHosts := range []int{3, 13} { countMut.Lock() veriCount = 0 countMut.Unlock() log.Lvl2("Running BFTCoSi with", nbrHosts, "hosts") local := sda.NewLocalTest() _, _, tree := local.GenBigTree(nbrHosts, nbrHosts, 3, true, true) done := make(chan bool) // create the message we want to sign for this round msg := []byte("Hello BFTCoSi") // Start the protocol node, err := local.CreateProtocol(tree, TestProtocolName) if err != nil { t.Fatal("Couldn't create new node:", err) } // Register the function generating the protocol instance var root *ProtocolBFTCoSi root = node.(*ProtocolBFTCoSi) root.Msg = msg // function that will be called when protocol is finished by the root root.RegisterOnDone(func() { done <- true }) go node.Start() // are we done yet? wait := time.Second * 3 select { case <-done: countMut.Lock() assert.Equal(t, veriCount, nbrHosts, "Each host should have called verification.") // if assert fails we don't care for unlocking (t.Fail) countMut.Unlock() sig := root.Signature() if err := cosi.VerifyCosiSignatureWithException(root.Suite(), root.AggregatedPublic, msg, sig.Sig, sig.Exceptions); err != nil { t.Fatal(fmt.Sprintf("%s Verification of the signature failed: %s", root.Name(), err.Error())) } case <-time.After(wait): t.Fatal("Waited", wait, "sec for BFTCoSi to finish ...") } local.CloseAll() } }
// Verify returns whether the verification of the signature succeeds or not. func (bs *BFTSignature) Verify(s abstract.Suite, agg abstract.Point, msg []byte) error { return cosi.VerifyCosiSignatureWithException(s, agg, msg, bs.Sig, bs.Exceptions) }