@@ 1,192 0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "os"
- "path"
-
- "github.com/kyoh86/xdg"
- "github.com/libp2p/go-libp2p-core/crypto"
- "github.com/mr-tron/base58/base58"
-)
-
-// where cached election info is stored
-var (
- tallyardConfigPath = path.Join(xdg.DataHome(), "tallyard")
- electionInfoFilePath = path.Join(tallyardConfigPath, "elections.json")
-)
-
-// maps an election's key to its cached info
-type ElectionInfos map[string]*ElectionInfo
-
-// an entry of an election's cached info
-type ElectionInfo struct{
- Candidates []Candidate
- PrivKey crypto.PrivKey
- PubKey crypto.PubKey
- RendezvousNonce Nonce
-}
-
-// used for JSON {en,de}coding
-type RawElectionInfos map[string]RawElectionInfo
-
-type RawElectionInfo struct{
- Candidates []string
- // Our private key in base58. TODO: encrypt
- PrivKey string
- // Our public key in base58. Kept in addition to the private key to
- // check against when the private key is later encrypted
- PubKey string
- RendezvousNonce string
-}
-
-// Saves an election's info into a file that can later be easily retrieved, even
-// on separate invocations of tallyard. Returns an error if there was one.
-func (e *Election) saveInfo() error {
- err := os.MkdirAll(tallyardConfigPath, 0700)
- if err != nil {
- return err
- }
- infos, err := loadPastElectionInfos()
- if err != nil {
- return fmt.Errorf("unable to load election info while saving election info: %s", err)
- }
- file, err := os.OpenFile(electionInfoFilePath,
- os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return fmt.Errorf("unable to open election info file: %s", err)
- }
- defer file.Close()
- localVoter := e.localVoter
- infos[e.electionKey] = &ElectionInfo{
- e.Candidates,
- localVoter.Peerstore().PrivKey(localVoter.ID()),
- localVoter.Peerstore().PubKey(localVoter.ID()),
- e.rendezvousNonce,
- }
- raw, err := marshalElectionInfos(infos)
- if err != nil {
- return fmt.Errorf("unable to marshal election info for cache file: %s", err)
- }
- err = encodeElectionsInfos(file, raw)
- if err != nil {
- return fmt.Errorf("unable to encode election info for cache file: %s", err)
- }
- return nil
-}
-
-// Checks whether we've joined this election before and attempts to retrieve its
-// info we cached for it. Useful if a connection was suddently lost and
-// tallyard had to restart. Returns the election's info (nil if no such info
-// exists) and an error
-func getElectionInfo(electionKey string) (*ElectionInfo, error) {
- infos, err := loadPastElectionInfos()
- if err != nil {
- return nil, fmt.Errorf("unable to get election info: %s", err)
- }
- if info, hasElectionKey := infos[electionKey]; hasElectionKey {
- return info, nil
- }
- return nil, nil
-}
-
-func loadPastElectionInfos() (ElectionInfos, error) {
- err := os.MkdirAll(tallyardConfigPath, 0700)
- if err != nil {
- return nil, err
- }
- file, err := os.OpenFile(electionInfoFilePath,
- os.O_RDONLY|os.O_CREATE, 0600)
- if err != nil {
- return nil, fmt.Errorf("unable to open election info file: %s", err)
- }
- defer file.Close()
- raw, err := decodeElectionInfos(file)
- if err != nil {
- return nil, fmt.Errorf("unable to decode election info for cache file: %s", err)
- }
- infos, err := unmarshalRawElectionInfos(raw)
- if err != nil {
- return nil, fmt.Errorf("unable to unmarshal election info for cache file: %s", err)
- }
- return infos, nil
-}
-
-func encodeElectionsInfos(writer io.Writer, rawElections RawElectionInfos) error {
- encoder := json.NewEncoder(writer)
- return encoder.Encode(rawElections)
-}
-
-func decodeElectionInfos(reader io.Reader) (rawElections RawElectionInfos, err error) {
- decoder := json.NewDecoder(reader)
- err = decoder.Decode(&rawElections)
- if err == io.EOF {
- return make(RawElectionInfos), nil
- }
- if err != nil {
- return nil, err
- }
- return rawElections, nil
-}
-
-func marshalElectionInfos(electionConfigs ElectionInfos) (rawElections RawElectionInfos, err error) {
- rawElections = make(RawElectionInfos)
- for electionKey, electionConfig := range electionConfigs {
- candidates := make([]string, 0, len(electionConfig.Candidates))
- for _, c := range electionConfig.Candidates {
- candidates = append(candidates, string(c))
- }
- privKeyBytes, err := crypto.MarshalPrivateKey(electionConfig.PrivKey)
- if err != nil {
- return nil, err
- }
- privKeyStr := base58.Encode(privKeyBytes)
- pubKeyBytes, err := crypto.MarshalPublicKey(electionConfig.PubKey)
- if err != nil {
- return nil, err
- }
- pubKeyStr := base58.Encode(pubKeyBytes)
- rawElections[electionKey] = RawElectionInfo{
- candidates,
- privKeyStr,
- pubKeyStr,
- string(electionConfig.RendezvousNonce),
- }
- }
- return rawElections, nil
-}
-
-func unmarshalRawElectionInfos(rawElections RawElectionInfos) (electionConfigs ElectionInfos, err error) {
- electionConfigs = make(ElectionInfos)
- for electionKey, info := range rawElections {
- candidates := make([]Candidate, 0, len(info.Candidates))
- for _, s := range info.Candidates {
- candidates = append(candidates, Candidate(s))
- }
- privKeyBytes, err := base58.Decode(info.PrivKey)
- if err != nil {
- return nil, err
- }
- privKey, err := crypto.UnmarshalPrivateKey(privKeyBytes)
- if err != nil {
- return nil, err
- }
- pubKeyBytes, err := base58.Decode(info.PubKey)
- if err != nil {
- return nil, err
- }
- pubKey, err := crypto.UnmarshalPublicKey(pubKeyBytes)
- if err != nil {
- return nil, err
- }
- electionConfigs[electionKey] = &ElectionInfo{
- candidates,
- privKey,
- pubKey,
- Nonce(info.RendezvousNonce),
- }
- }
- return electionConfigs, nil
-}
@@ 1,65 0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
- "testing"
-)
-
-const (
- electionKey0 = "DpgZ3EG8cyNAxrbGejTTUuJB6KkvKVGK9WEpQWDh6RLd0QmVitsctABm8xbadtkqU46WMLCjuAadUR2RAkjaPf7xz7X"
- electionKey1 = "Dmfo6renA9YKuTFdGL4iSP5fcHbxHG4Qc9XTHkBzdHPa0QmVjm2QACdwMYguMtMooDoLsiagyVfe7qwxpuzUmX1stTM"
-)
-
-var rawElectionInfosRef = RawElectionInfos{
- electionKey0:
- {
- PrivKey: "7r1r8iBFRYi5hLWbNS5vx53fAvnyFFGrgnDEwu8DSGRVdik5TVuPhCBpqummjaMMXgogcoz6h88rEWvM1af5G4VV4t5cNeFF6hXDyM14gxAMBkm2cEgpcf7d3AAH4auiHhZcB5XWUZeGKUgjz2WGtLPChHhAZzCA8GnDZHhrLSL2qfSt1ZYhyyvTLbEvfNZ7VhwXK64Y4UxjaRAXsMpBCret9aAck9pJxJnE5gm91JxTQybcTKULN9BxvJV99kLUdZ66PJ6ff5TZB4oNzShEQcdyP2G8tUJkCujokXWpZQh7ZDE4dtuoP6uvQhYSkPtWTgYv888BRYDoNDDqWc1nqZGqftr5EHogUTC4H7D3UWngVpwd1Mjbi8vS2DicKDXwJqP2bSyeVGLG3yLkWyjfxfBwNwnHGcBmhiSrL6bHfUrpJqy95UPC3ZSJeLNaYEToQAJmCEah4D7BZchF13rXjLGMsXxTUTHt9mMmEa8jdxLbqUkafVsN1VcHeZBVScvnFCS1e4xe1Ja54xg8H7b5HddB8JcSHaW2fJkvTrr3avT24NivAw4nvRg5UasMR2WMzgYP1rkmyV5vyPoJAnytYX8hZp2zX6gPbZBqUEDAQcvAegibjcDhRZMxMLCrR73UReEqXjjFhKYh7AsDz6uNDrwE6oVRJZ9GLBAetQ9HothETXr2PUaFkh82zCCCYbNL16aFWgiKYBAd1iaKL7idA4GrzTXuYR5HHJxcGSXNc9mUrGEEY2tLkNLPk3VHrqEDpzKArA72PGy1mKXVghoaJeZAe5am49ZPuPG4VQnkxHXB8NkhPkc26cbD6iYxq1cC7XDEMrQ8ggvecjhFxVnnFsDE2Ub7cZyVompvckPMX7R7VuERq7Ax1Vk4qNgbP5hHpn5F5DGpRNRdtpsEpzseSvBKQ6nDknSXFYSya99b4T7nwVkYCj7KuD21Xfmj4mRYQxy4aebKggUvPWAmMNSTWdrPK9QF7Y2cwagpDYQx8KEcVgGU5CrCeKscAbc84PbP6H2HMaMB5ivdMmuEbQfJuyMpX7sXwXCvHUg4p8R4UMf7nkF5c76H4oRH2CaJnnQ25DwYtMtfWmidTFFJECtaLU154z47L2TzNtn3G16UtUNvyLBA5b5HBKhKcjzwVHmRBreWz3urCF1obBT49mERb9mrsyicYjfoKqXS1mVVVCkvs1vAEm73RepXBHD37aQ4DVk9ThFB2RMiDxCwaW7EYUkNLpRaH1FHPJg2o9x1EkPsqcTg5TL31e3EctivtyLCVPLsaUsFYFmzyXCsniXeJPdPGxvt32fbeP1GUXv8N2xLAoVg815cuEnGvkjvztLK8Mv2fxtsPGQaEH6D9FEM2x1xRAFj6cspkbC5RpEbTcuEaaXBpBgVZSxT7TkYWUyerSYKLhocacwmGSYgduxvTB5w1nTfbk3sobEEjCrZwZjiQzdwkrP1iG4x1YDSB4f97n7gnbkEs5LDvuDwgS6KBeWnWTw1V2P5U8VkTCFhj6UAiv1FP9Tdi664MgDVNXQoEGQryy98zShcyg3BZ2Jr8yCdri3gVgMLG7b6Q91AXehz4RRs2X6SrZtCLKN2uBmhGwntvL2FvXDkGanXuRfUEMP8g2VdtWuW8",
- PubKey: "7ySHQR7YZJApfZRKds9hzzFypZo8s6WQyZqXCYVHRjug84TSqhdKgdVBhS3cZ6NYMfygyfPMvAgjnn2mp3c5dSME49opHiD3ioUaArqGqddyWf3gonWVfnjkTnMcdpGXvDt74uAYf2NrwsphN1MuBBX5NAoHtE5vTRMAiZL94KSg7qFNZM1PckSJfo4xJUD1JgmEMqBvavosjFoenhZv7FjLkXFJhHFGfF7KaK4Q62bUubYtgiR1bkYk1RtctkjUvnBW8YnSx1QFGrmA5qAz8ZUCRmeqgktvpYDR2bj3XFDUGmjqNG3N4QMikg2a6vquCuuT6kv5WefzUYncvijQLHx85z74F8wMZV5huUxQM3RS2aZgc89WvFjeP5Pkmv1bUqvdZ5n1Yi3U65b9KBCR9ycL",
- },
- electionKey1:
- {
- PrivKey: "B9bLmHeKLQU1hX23meSn2kJP4wwPAGeaXRpYnkZyKfR98RYs51wo7syA9N7oSbcf49hyrp9vaFpo2GA9yYkiWsPh3smeDDbSZsuzNoAZXr4tjPFytaaddvbsbsme5YbdMejRh1qPncRR6vmhBwb9r4xZBugb2PZPNbqBKKkVotF3YzVzJ3s6kjKyTirGW8xowFbma8hwWntfaNVuZF143BeHQMjyAB5QYRtLtx85RS4Zkxm4wv71Y5ZAcf3VMgmjGXTVXivWX4pkDHBSYfXYr6CoqLy4iNNWstnehBVPAJFM9YvYTnoT3DYXyXXgBSnfPLXFgX9yxkKh8YtXVNKewLqa3b9uKHzCh1FbxTEThfTK1Q4YPFLEek8eR2DUHinGuPrEgCmH4H8ZKXmfLkmGTgHWDkzDr4u2e74jE7Fz9XWmwHq39ZzUsE5SFVWVm6domENEgQMPHU83X7RFXPwgfCCiNdNYkozL9hvBgPujDtiiyBPExbUqY5dnCceTuD6ysJmhwL4SHWpdHKZwwWETWeDTzyA7snZjbebcmE1visFydZ2UQaQdHKnNU5gV2NkiQupyyCEvs9rrHW6xf6g9myMrzdRQVRBBuKswCjq91CNA2uAtkyNLzEhD9GSLuGFRgmtzEwGxek2p12ysUjJyfgBDY28CoMJVJfeK8dyCHQnyvtmA32uxQ8m83QDRxTGY52ubsLaKm9n1L4MiJKW73BC8JoZxdQmuW8278JUAWdTK7KDk2yCDfFfUwGLq6Jz1aTqV5KM23Ysjto6ENeYSHiNrwJ4yBCP2cq4bs48dfdCqWodzBN2HaUpiFiPfQDG5r52zow1aULEaLeUrUbCChKTi6WqWyEBKxEpVMiL7dRQqzHyq3JAFyu51CgmbfFyQtamV8ULE4aVMotrCm2QcrvWxLxkjvSb4cCcnJwyQ9QyT8jFpfVnDWSdLSpbRAxJzr4c4pxWMDjhhPfQYWLArMTv7N6woQwMg8L6AJVbm96qQQ8v99VHVRzib4gVP36DYmTT8WEks2LtFXBwypU8x17iREvwex2ZXHQgvYRAkgw1uYg8rkGMQ5ZTrekTbbsBnUxmcV7Y5Cb18PUVeTRvDtFUB8K2VsZZeTnfWsfvKNqURs4nLyn4VPicgtUbDwLvJnpijDfodv6ydYfbdpDEtkGrKXKwNTwWZPFAts61Wnsouu7dLCN2gKWfhh8x4NdcnZP3fKE15GfLViFMeanAZvww2DVyW78cXpeztanCmkbUqLSvoGkRJsZ49pFEtVeGv1at6SFNKYzyPCWYnegfvs2f54rUKCchWDoNZwYw7fja32d87qEUzWouorLXc4ATkykaKzHthoiwEMjweQKGgGgUXbNbP56x1jZYgLPSCVHHgGaLNKgqW6tSXEKThEEg42kzDNiymr7soWwGrZPsNyE5vpfoxd7ebeKy2LJ4H9AwqAbUFhuFAFwzcTRLsiWGJKg9ysi8fpcGBcg7NbrrkHwsR1jvvpV7f855pRTPMXCUQpYiGWVPtJ1UZAsmX5RqVmgfdyJHYok8aL2XML9GeHTHZZNg7iD2ST8DSdKNhaYs7oxyTMvWsWnqPezUq5kaQxRa8zTkFqUJYUAgiZrKDFrgsXC4EgboyZM3CK",
- PubKey: "7ySHQR7YZJApfZRKds9hzzFypZo8s6WQyZqXCYVHRjug84TSqhdKDnnZpz69WtL8kvTgtrjEF3GHmsfjgMSt2t7vYgU26qHZfCXPUhA9u93vkCXSG6ZLBWw8K2HxMWPR69LoWzCsfXnLnw9mbr64uHmEeP64PSidtyshApUS73ikt7KGMdk3twJLr7SZ8uaqw6DCvBd9po5tVtPZ9gS1NPG3vuavLfm2P9YT2LMzCf68bJmqzgiVpUxRemvpwppVP675C5m6ctDELBTvqwQ9dc8baG4ztZPehEeUhULG5JpgtMKayCYRNhQVKdENyWXfFYzpMJ27iMH3LT2dixjgXRkqh8PKFt1srJA4we6vCLx1yjDjJV7MELo9P9nkXbojjQLXnqa41bYYGMN4ChK1C78U",
- },
-}
-
-func TestRawElectionInfosDecoding(t *testing.T) {
- jsonStream := fmt.Sprintf(`
- {"%s": {"PrivKey": "%s",
- "PubKey": "%s"},
- "%s": {"PrivKey": "%s",
- "PubKey": "%s"}}`,
- electionKey0,
- rawElectionInfosRef[electionKey0].PrivKey,
- rawElectionInfosRef[electionKey0].PubKey,
- electionKey1,
- rawElectionInfosRef[electionKey1].PrivKey,
- rawElectionInfosRef[electionKey1].PubKey,
- )
- rawElections, err := decodeElectionInfos(strings.NewReader(jsonStream))
- if err != nil {
- panic(err)
- }
- if len(rawElections) != 2 {
- t.FailNow()
- }
- if _, exists := rawElections[electionKey0]; !exists {
- t.FailNow()
- }
- if _, exists := rawElections[electionKey1]; !exists {
- t.FailNow()
- }
- if rawElections[electionKey0].PrivKey != rawElectionInfosRef[electionKey0].PrivKey {
- t.FailNow()
- }
- if rawElections[electionKey1].PrivKey != rawElectionInfosRef[electionKey1].PrivKey {
- t.FailNow()
- }
- if rawElections[electionKey0].PubKey != rawElectionInfosRef[electionKey0].PubKey {
- t.FailNow()
- }
- if rawElections[electionKey1].PubKey != rawElectionInfosRef[electionKey1].PubKey {
- t.FailNow()
- }
-}
@@ 61,25 61,7 @@ func NewElectionWithElectionKey(electionKey string) *Election {
localVoter *LocalVoter
rendezvousNonce Nonce
)
- // try to recover info from elections file to see if we've
- // joined/created this election before
- electionInfo, err := getElectionInfo(electionKey)
- if err != nil {
- panic(err)
- }
- if electionInfo != nil { // we've joined this election before
- // ensure public key from config is same as one derived from
- // private key
- candidates = electionInfo.Candidates
- if !electionInfo.PrivKey.GetPublic().Equals(electionInfo.PubKey) {
- // TODO: handle properly
- panic("loaded public key does not match derived one from private key")
- }
- localVoter = NewLocalVoter(libp2p.Identity(electionInfo.PrivKey))
- rendezvousNonce = electionInfo.RendezvousNonce
- } else { // we've never joined this election before
- localVoter = NewLocalVoter(libp2p.RandomIdentity)
- }
+ localVoter = NewLocalVoter(libp2p.RandomIdentity)
e := &Election{
Candidates: candidates,
electionKey: electionKey,
@@ 92,6 74,7 @@ func NewElectionWithElectionKey(electionKey string) *Election {
panic("invalid election key")
}
logger.Info("merkle root:", electionKey[:zeroi])
+ var err error
e.merkleRoot, err = base58.Decode(electionKey[:zeroi])
if err != nil {
panic(err)