/* * Reads in the config for the application - * also parses the init-flags and connects to * the monitor. */ func ReadConfig(conf interface{}, dir ...string) { var err error err = ReadTomlConfig(conf, "app.toml", dir...) if err != nil { log.Fatal("Couldn't load app-config-file in exec") } debug := reflect.ValueOf(conf).Elem().FieldByName("Debug") if debug.IsValid() { dbg.DebugVisible = debug.Interface().(int) } FlagInit() flag.Parse() dbg.Lvlf3("Flags are %+v", RunFlags) if RunFlags.AmRoot { if err := monitor.ConnectSink(RunFlags.Logger); err != nil { dbg.Fatal("Couldn't connect to monitor", err) } } dbg.Lvl3("Running", RunFlags.Hostname, "with logger at", RunFlags.Logger) }
// This is the leader who waits for all connections and then sends the // message to be signed func GoLeader(conf *app.NaiveConfig) { host := net.NewTcpHost(app.RunFlags.Hostname) key := cliutils.KeyPair(suite) leader := NewPeer(host, LeadRole, key.Secret, key.Public) // Setting up the connections // notably to the monitoring process if app.RunFlags.Logger != "" { monitor.ConnectSink(app.RunFlags.Logger) } else { monitor.EnableMeasure(false) } msg := []byte("Hello World\n") // Listen for connections dbg.Lvl3(leader.String(), "making connections ...") // each conn will create its own channel to be used to handle rounds roundChans := make(chan chan chan *net.BasicSignature) // Send the message to be signed proto := func(c net.Conn) { // make the chan that will receive a new chan // for each round where to send the signature roundChan := make(chan chan *net.BasicSignature) roundChans <- roundChan n := 0 // wait for the next round for sigChan := range roundChan { dbg.Lvl3(leader.String(), "Round", n, "sending message", msg, "to signer", c.PeerName()) leader.SendMessage(msg, c) dbg.Lvl3(leader.String(), "Round", n, "receivng signature from signer", c.PeerName()) sig := leader.ReceiveBasicSignature(c) sigChan <- sig n += 1 } c.Close() dbg.Lvl3(leader.String(), "closed connection with signer", c.PeerName()) } // Connecting to the signer setup := monitor.NewMeasure("setup") go leader.Listen(app.RunFlags.Hostname, proto) dbg.Lvl3(leader.String(), "Listening for channels creation..") // listen for round chans + signatures for each round masterRoundChan := make(chan chan *net.BasicSignature) roundChanns := make([]chan chan *net.BasicSignature, 0) numberHosts := len(conf.Hosts) // Make the "setup" of channels for { ch := <-roundChans roundChanns = append(roundChanns, ch) //Received round channels from every connections- if len(roundChanns) == numberHosts-1 { // make the Fanout => master will send to all go func() { // send the new SignatureChannel to every conn for newSigChan := range masterRoundChan { for i, _ := range roundChanns { go func(j int) { roundChanns[j] <- newSigChan }(i) } } //close when finished for _, c := range roundChanns { close(c) } }() break } } setup.Measure() dbg.Lvl3(leader.String(), "got all channels ready => starting the", conf.Rounds, "rounds") // Starting to run the simulation for conf.Rounds rounds roundM := monitor.NewMeasure("round") for round := 0; round < conf.Rounds; round++ { // Measure calculation time calc := monitor.NewMeasure("calc") dbg.Lvl1("Server starting round", round+1) n := 0 faulty := 0 // launch a new round connChan := make(chan *net.BasicSignature) masterRoundChan <- connChan // Wait each signatures sigs := make([]*net.BasicSignature, 0) for n < numberHosts-1 { bs := <-connChan sigs = append(sigs, bs) n += 1 } // All sigs reeived <=> all calcs are done calc.Measure() // verify each signatures if conf.SkipChecks { dbg.Lvl3("Skipping check for round", round) } else { // Measure verificationt time verify := monitor.NewMeasure("verify") for _, sig := range sigs { if err := SchnorrVerify(suite, msg, *sig); err != nil { faulty += 1 dbg.Lvl1(leader.String(), "Round", round, "received a faulty signature!") } else { dbg.Lvl3(leader.String(), "Round", round, "received Good signature") } } verify.Measure() } roundM.Measure() dbg.Lvl3(leader.String(), "Round", round, "received", len(conf.Hosts)-1, "signatures (", faulty, "faulty sign)") } // Close down all connections close(masterRoundChan) dbg.Lvl3(leader.String(), "has done all rounds") }
func RunRoot(conf *app.NTreeConfig) { host := net.NewTcpHost(app.RunFlags.Hostname) key := cliutils.KeyPair(suite) peer := NewPeer(host, LeadRole, key.Secret, key.Public) dbg.Lvl3(peer.String(), "Up and will make connections...") // monitor if app.RunFlags.Logger == "" { monitor.EnableMeasure(false) } else { if err := monitor.ConnectSink(app.RunFlags.Logger); err != nil { dbg.Fatal(peer.String(), "could not connect to the monitor:", err) } } // msg to be sent + signed msg := []byte("Hello World") // make setup measurement setup := monitor.NewMeasure("setup") // masterRoundChan is used to tell that everyone is ready masterRoundChan := make(chan chan chan *net.ListBasicSignature) // Open connection for each children for _, c := range conf.Tree.Children { dbg.Lvl3(peer.String(), "will connect to children", c.Name) connPeer := peer.Open(c.Name) if connPeer == nil { dbg.Fatal(peer.String(), "Could not open connection to child", c.Name) } // then start Root protocol go func(conn net.Conn) { dbg.Lvl3(peer.String(), "connected to children", conn.PeerName()) roundSigChan := make(chan chan *net.ListBasicSignature) // notify we are ready to begin masterRoundChan <- roundSigChan // each rounds... for lsigChan := range roundSigChan { dbg.Lvl4(peer.String(), "starting new round with", conn.PeerName()) m := net.MessageSigning{ Length: len(msg), Msg: msg, } // send msg to children err := conn.Send(m) if err != nil { dbg.Fatal(peer.String(), "could not send message to children", conn.PeerName(), ":", err) } dbg.Lvl3(peer.String(), "sent message to children", conn.PeerName()) // Receive bundled signatures sig, err := conn.Receive() if err != nil { dbg.Fatal(peer.String(), "could not received bundled signature from", conn.PeerName(), ":", err) } if sig.MsgType != net.ListBasicSignatureType { dbg.Fatal(peer.String(), "received a wrong packet type from", conn.PeerName(), ":", sig.MsgType.String()) } // Then pass them on sigs := sig.Msg.(net.ListBasicSignature) lsigChan <- &sigs dbg.Lvl3(peer.String(), "Received list of signatures from child", conn.PeerName()) } }(connPeer) } // First collect every "ready-connections" children := make([]chan chan *net.ListBasicSignature, 0) for round := range masterRoundChan { children = append(children, round) if len(children) == len(conf.Tree.Children) { dbg.Lvl3(peer.String(), "collected each children channels") break } } close(masterRoundChan) setup.Measure() // Then for each rounds tell them to start the protocol round := monitor.NewMeasure("round") for i := 1; i <= conf.Rounds; i++ { dbg.Lvl1(peer.String(), "will start a new round", i) calc := monitor.NewMeasure("calc") // the signature channel used for this round lsigChan := make(chan *net.ListBasicSignature) // notify each connections for _, ch := range children { ch <- lsigChan } childrenSigs := make([]*net.ListBasicSignature, 0) // Wait for listsignatures coming dbg.Lvl3(peer.String(), "Waiting on signatures for round", i, "...") for sigs := range lsigChan { dbg.Lvl3(peer.String(), "will analyze one ListBasicSignature...") childrenSigs = append(childrenSigs, sigs) // we have received all bundled signatures so time it if len(childrenSigs) == len(conf.Tree.Children) { close(lsigChan) // we have finished for this round } } dbg.Lvl3(peer.String(), "Received all signatures ... ") calc.Measure() var verifyWg sync.WaitGroup var faulty uint64 = 0 var total uint64 = 0 // start timing verification verify := monitor.NewMeasure("verify") for _, sigs := range childrenSigs { // Here it launches one go routine to verify a bundle verifyWg.Add(1) go func(s *net.ListBasicSignature) { defer verifyWg.Done() if conf.SkipChecks { return } // verify each independant signatures for _, sig := range s.Sigs { if err := SchnorrVerify(suite, msg, sig); err != nil { dbg.Lvl2(peer.String(), "received incorrect signature ><", err) atomic.AddUint64(&faulty, 1) } atomic.AddUint64(&total, 1) } }(sigs) } // wait for all verifications verifyWg.Wait() // finished verifying => time it ! verify.Measure() round.Measure() dbg.Lvl3(peer.String(), "Round", i, "/", conf.Rounds, "has verified all signatures:", total-faulty, "/", total, "good signatures") } // cLosing each channels for _, ch := range children { close(ch) } dbg.Lvl2(peer.String(), "Finished all rounds successfully.") }
func main() { // First, let's read our config // You should create your own config in lib/app. // TOML is a pretty simple and readable format // Whatever information needed, supply it in the simulation/.toml file that // will be parsed into your ConfigSkeleton struct. conf := &app.ConfigSkeleton{} app.ReadConfig(conf) // we must know who we are if app.RunFlags.Hostname == "" { dbg.Fatal("Hostname empty: Abort") } // Do some common setup if app.RunFlags.Mode == "client" { app.RunFlags.Hostname = app.RunFlags.Name } hostname := app.RunFlags.Hostname // i.e. we are root if hostname == conf.Hosts[0] { dbg.Lvlf3("Tree is %+v", conf.Tree) } dbg.Lvl3(hostname, "Starting to run") // Connect to the monitor process. This monitor process is run on your // machine and accepts connections from any node, usually you only connect // with the root for readability and performance reasons (don't connect to // your machine from 8000 nodes .. !) if app.RunFlags.Logger != "" { monitor.ConnectSink(app.RunFlags.Logger) } else { dbg.Fatal("No logger specified") } // Here you create a "Peer",that's the struct that will create a new round // each seconds and handle other subtleties for you peer := conode.NewPeer(hostname, conf.ConfigConode) // The root waits everyone's to be up if app.RunFlags.AmRoot { for { time.Sleep(time.Second) setupRound := sign.NewRoundSetup(peer.Node) peer.StartAnnouncementWithWait(setupRound, 5*time.Second) counted := <-setupRound.Counted dbg.Lvl1("Number of peers counted:", counted) if counted == len(conf.Hosts) { dbg.Lvl1("All hosts replied") break } } } // You register by giving the type, and a function that takes a sign.Node in // input (basically the underlying protocol) and returns a Round. sign.RegisterRoundFactory(RoundSkeletonType, func(node *sign.Node) sign.Round { return NewRoundSkeleton(node) }) // Here it will create a new round each seconds automatically. // If you need more fined grained control, you must implement yourself the // conode.Peer struct (it's quite easy). peer.LoopRounds(RoundSkeletonType, conf.Rounds) // Notify the monitor that we finished so that the simulation can be stopped monitor.End() }