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
		}
	}
}