From 4675b943ab8e844c8d5198ec600bec861845e021 Mon Sep 17 00:00:00 2001 From: David Florness Date: Fri, 5 Jun 2020 02:43:29 -0600 Subject: [PATCH] Use merkle tree in election key to verify election options --- go.mod | 2 ++ go.sum | 4 +++ main.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 52fc96c..db32967 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module gitlab.com/edwargix/tallyard require ( + github.com/cbergoon/merkletree v0.2.0 github.com/gogo/protobuf v1.3.1 github.com/google/uuid v1.1.1 github.com/ipfs/go-datastore v0.4.2 @@ -17,6 +18,7 @@ require ( github.com/libp2p/go-libp2p-secio v0.2.1 github.com/libp2p/go-libp2p-swarm v0.2.2 github.com/libp2p/go-libp2p-tls v0.1.3 + github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-multiaddr v0.2.0 github.com/multiformats/go-multiaddr-net v0.1.2 github.com/rivo/tview v0.0.0-20200528200248-fe953220389f diff --git a/go.sum b/go.sum index 9f65aaa..63b8452 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cbergoon/merkletree v0.2.0 h1:Bttqr3OuoiZEo4ed1L7fTasHka9II+BF9fhBfbNEEoQ= +github.com/cbergoon/merkletree v0.2.0/go.mod h1:5c15eckUgiucMGDOCanvalj/yJnD+KAZj1qyJtRW5aM= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -281,6 +283,8 @@ github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVq github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= diff --git a/main.go b/main.go index 3569416..db8d349 100644 --- a/main.go +++ b/main.go @@ -2,11 +2,16 @@ package main import ( "bufio" + "bytes" "context" + "crypto/sha256" "fmt" "io" + "os" + "strings" "sync" + "github.com/cbergoon/merkletree" "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p-core/host" @@ -15,21 +20,40 @@ import ( "github.com/libp2p/go-libp2p-core/protocol" dht "github.com/libp2p/go-libp2p-kad-dht" routing "github.com/libp2p/go-libp2p-routing" + "github.com/mr-tron/base58/base58" "github.com/rivo/tview" "github.com/whyrusleeping/go-logging" ) +type ElectionOption string + var ( Logger = log.Logger("tallyard") ProtocolID = protocol.ID("/tallyard/0.0.0") - electionOptions []string + electionOptions []ElectionOption + optionsMerkle *merkletree.MerkleTree + + merkleRoot []byte masterID peer.ID + ctx context.Context h host.Host kdht *dht.IpfsDHT ) +func (eo ElectionOption) CalculateHash() ([]byte, error) { + h := sha256.New() + if _, err := h.Write([]byte(string(eo))); err != nil { + return nil, err + } + return h.Sum(nil), nil +} + +func (eo ElectionOption) Equals(other merkletree.Content) (bool, error) { + return string(eo) == string(other.(ElectionOption)), nil +} + func masterStreamHandler(stream network.Stream) { Logger.Info("got a new stream!") writer := bufio.NewWriter(stream) @@ -64,9 +88,16 @@ func createElection() { AddButton("Done", func() { // TODO: ensure none of the candidates are empty app.Stop() + var content []merkletree.Content for i := 0; i < n-1; i++ { - electionOptions = append(electionOptions, - form.GetFormItem(i).(*tview.InputField).GetText()) + eo := ElectionOption(form.GetFormItem(i).(*tview.InputField).GetText()) + electionOptions = append(electionOptions, eo) + content = append(content, eo) + } + var err error + optionsMerkle, err = merkletree.NewTree(content) + if err != nil { + panic(err) } }) if err := app.SetRoot(form, true).EnableMouse(true).Run(); err != nil { @@ -78,11 +109,20 @@ func joinElection() { app := tview.NewApplication() var form *tview.Form form = tview.NewForm(). - AddInputField("Master peer ID:", "", 50, nil, nil). + AddInputField("Election key:", "", 50, nil, nil). AddButton("Continue", func() { - var err error app.Stop() - masterID, err = peer.Decode(form.GetFormItem(0).(*tview.InputField).GetText()) + electionKey := form.GetFormItem(0).(*tview.InputField).GetText() + + zeroi := strings.IndexByte(electionKey, '0') + var err error + merkleRoot, err = base58.Decode(electionKey[:zeroi]) + if err != nil { + panic(err) + } + Logger.Info("merkle root:", merkleRoot) + + masterID, err = peer.Decode(electionKey[zeroi+1:]) if err != nil { panic(err) } @@ -93,6 +133,24 @@ func joinElection() { } } +func checkMerkle() { + var content []merkletree.Content + var err error + for _, eo := range electionOptions { + content = append(content, eo) + } + optionsMerkle, err = merkletree.NewTree(content) + if err != nil { + panic(err) + } + if bytes.Compare(optionsMerkle.MerkleRoot(), merkleRoot) == 0 { + fmt.Println("options merkle verification succeeded!") + } else { + fmt.Println("options merkle verification failed; exiting") + os.Exit(1) + } +} + func bootstrap() { var err error @@ -135,6 +193,10 @@ func bootstrap() { wg.Wait() if masterID == "" { // we are the master + fmt.Println("share this with peers:") + fmt.Printf("%s0%s\n", + base58.Encode(optionsMerkle.MerkleRoot()), + h.ID()) Logger.Info("waiting for incoming streams...") h.SetStreamHandler(ProtocolID, masterStreamHandler) } else { // we are a slave @@ -155,10 +217,12 @@ func bootstrap() { if str[len(str)-1] == '\n' { str = str[:len(str)-1] } + electionOptions = append(electionOptions, ElectionOption(str)) fmt.Println(str) } stream.Close() Logger.Info("stream with master peer closed") + checkMerkle() } } -- 2.38.4