func runClientProtocol(configFilePath string) (bool, error) { // first stage, let's retrieve everything from // the configuration file that the client needs var config SchnorrMGroupConfig suite := ed25519.NewAES128SHA256Ed25519(true) fcontents, err := ioutil.ReadFile(configFilePath) if err != nil { fmt.Println("Error reading file") fmt.Println(err.Error()) os.Exit(1) } err = json.Unmarshal(fcontents, &config) if err != nil { fmt.Println("Error unmarshalling") fmt.Println(err.Error()) os.Exit(1) } // and now, for our next trick, a random 1KB blob randomdata := make([]byte, 1024) _, err = rand.Read(randomdata) if err != nil { fmt.Println(err.Error()) return false, err } reportChan := make(chan controllerMessage) var syncChans []chan []byte for i, _ := range config.Members { syncChan := make(chan []byte) syncChans = append(syncChans, syncChan) fmt.Println("CLIENT", "C", "Launching goroutine worker") go serverComms(config, i, randomdata, reportChan, syncChan) } var respCount int = 0 commitmentArray := make([]crypto.SchnorrMPublicCommitment, len(config.Members), len(config.Members)) fmt.Println("CLIENT", "C", "Controller getting ready to receive") for { select { case msg := <-reportChan: // we should probably check all our client threads have responded // once and only once, but we won't buf := bytes.NewBuffer(msg.Message) commitment := crypto.SchnorrMPublicCommitment{} err := abstract.Read(buf, &commitment, suite) if err != nil { fmt.Println("CLIENT", "Read Error") fmt.Println(err.Error()) return false, err } // we have our abstract point. // let's go fmt.Println("CLIENT", "C", "Controller got message index", msg.MemberIndex) commitmentArray[msg.MemberIndex] = commitment respCount = respCount + 1 default: } if respCount == len(config.Members) { // reset and break respCount = 0 break } } fmt.Println("CLIENT", "C", "Controller received all responses, preparing to aggregate") // sum the points aggregateCommmitment := crypto.SchnorrMComputeAggregateCommitment(suite, commitmentArray) collectiveChallenge := crypto.SchnorrMComputeCollectiveChallenge(suite, randomdata, aggregateCommmitment) bAggregateCommmitment := bytes.Buffer{} abstract.Write(&bAggregateCommmitment, &aggregateCommmitment, suite) // report for _, ch := range syncChans { fmt.Println("CLIENT", "C", "Sending aggcommitbytes back to workers") ch <- bAggregateCommmitment.Bytes() } // now wait for the server responses, aggregate them and compute // a signature from the combined servers. fmt.Println("CLIENT", "C", "Controller getting ready to receive") responseArray := make([]crypto.SchnorrMResponse, len(config.Members), len(config.Members)) for { select { case msg := <-reportChan: // we should probably check all our client threads have responded // once and only once, but we won't buf := bytes.NewBuffer(msg.Message) response := crypto.SchnorrMResponse{} err := abstract.Read(buf, &response, suite) if err != nil { return false, err } fmt.Println("CLIENT", "C", "Received from", msg.MemberIndex) // we have our abstract point. // let's go responseArray[msg.MemberIndex] = response respCount = respCount + 1 fmt.Println("CLIENT", "C", "Received responses", respCount) default: } if respCount == len(config.Members) { break } } sig := crypto.SchnorrMComputeSignatureFromResponses(suite, collectiveChallenge, responseArray) fmt.Println("Signature created, is") fmt.Println(sig) return true, nil }
func signOneKBMSchnorr(conn net.Conn, suite abstract.Suite, kv crypto.SchnorrKeyset) { defer conn.Close() fmt.Println(suite) ch := make(chan []byte) errorCh := make(chan error) // this neat little routine for wrapping read connections // in a class unashamedly stolen from stackoverflow: // http://stackoverflow.com/a/9764191 go func(ch chan []byte, eCh chan error) { for { // try to read the data fmt.Println("SERVER", "Read goroutine off and going") buffer := make([]byte, 1026) _, err := conn.Read(buffer) if err != nil { // send an error if it's encountered errorCh <- err return } // send data if we read some. ch <- buffer } }(ch, errorCh) var internalState byte = INIT var message []byte var aggregateCommitment crypto.SchnorrMAggregateCommmitment var privateCommit crypto.SchnorrMPrivateCommitment for { select { case data := <-ch: // validate state transition - we can only // transfer to the next state in the protocol // anything else and we simply ignore the message // eventually we time out and close the connection newState := data[0] fmt.Println("SERVER", "Selected data channel, states are", newState, internalState) if newState != (internalState + 1) { continue } internalState = newState payload := data[2:] switch newState { case MESSAGE: fmt.Println("SERVER", "Received Message") message = payload privateCommitment, err := crypto.SchnorrMGenerateCommitment(suite) if err != nil { fmt.Println("Error generating commitment") fmt.Println(err.Error()) break } privateCommit = privateCommitment publicCommitment := privateCommitment.PublicCommitment() buf := bytes.Buffer{} abstract.Write(&buf, &publicCommitment, suite) conn.Write(buf.Bytes()) case COMMITMENT: fmt.Println("SERVER", "Received Commitment") buf := bytes.NewBuffer(payload) err := abstract.Read(buf, &aggregateCommitment, suite) if err != nil { fmt.Println("Error binary decode of aggregateCommitment") fmt.Println(err.Error()) break } collectiveChallenge := crypto.SchnorrMComputeCollectiveChallenge(suite, message, aggregateCommitment) response := crypto.SchnorrMUnmarshallCCComputeResponse(suite, kv, privateCommit, collectiveChallenge) outBuf := bytes.Buffer{} abstract.Write(&outBuf, &response, suite) conn.Write(outBuf.Bytes()) // we're now at the end, we can break and close connection break default: fmt.Println("Didn't understand message, received:") fmt.Println(data) } case err := <-errorCh: if err == io.EOF { return } // we should, really, log instead. fmt.Println("Encountered error serving client") fmt.Println(err.Error()) break // well, the *idea* was to have this but frustratingly // it does not compile. Oh well. //case time.Tick(time.Minute): // more robust handling of connections. // don't allow clients to hold the server open // indefinitely. //break } } }