M election/map.go => election/map.go +1 -1
@@ 29,7 29,7 @@ type ElectionsMap struct {
save func(*ElectionsMap) `json:"-"`
}
-const electionsMapVersion = 6
+const electionsMapVersion = 7
func NewElectionsMap(userID id.UserID, save func(*ElectionsMap)) *ElectionsMap {
return &ElectionsMap{
M election/marshal.go => election/marshal.go +79 -36
@@ 1,67 1,110 @@
package election
import (
- "bytes"
- "encoding/base64"
+ "os"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16"
+ "github.com/kyoh86/xdg"
+ log "github.com/sirupsen/logrus"
+ "maunium.net/go/mautrix/appservice"
)
-type MarshallableProvingKey struct {
- Pk groth16.ProvingKey
+func init() {
+ os.MkdirAll(xdg.DataHome() + "/tallyard/files", 0700)
}
-func (t *MarshallableProvingKey) UnmarshalJSON(b []byte) error {
- var buf bytes.Buffer
- _, err := buf.Write(bytes.Trim(b, "\""))
+func filePath(fileID string) string {
+ return xdg.DataHome() + "/tallyard/files/" + fileID
+}
+
+type ProvingKeyFile struct {
+ FileID string `json:"file_id"`
+ pk groth16.ProvingKey `json:"-"`
+}
+
+func NewProvingKeyFile(fileID string, pk groth16.ProvingKey) *ProvingKeyFile {
+ filePath := filePath(fileID)
+ file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
- return err
+ log.Errorf("couldn't open file %s; this proving key will be discarded upon exit: %s", filePath, err)
+ return &ProvingKeyFile{"", pk}
+ }
+ _, err = pk.WriteTo(file)
+ if err != nil {
+ log.Errorf("couldn't write proving key to file %s; this proving will be discarded upon exit: %s", filePath, err)
+ return &ProvingKeyFile{"", pk}
+ }
+ return &ProvingKeyFile{
+ FileID: fileID,
+ pk: pk,
}
- t.Pk = groth16.NewProvingKey(ecc.BLS12_381)
- _, err = t.Pk.ReadFrom(base64.NewDecoder(base64.StdEncoding, &buf))
- return err
}
-func (t *MarshallableProvingKey) MarshalJSON() ([]byte, error) {
- var buf bytes.Buffer
- encoder := base64.NewEncoder(base64.StdEncoding, &buf)
- _, err := t.Pk.WriteTo(encoder)
+func (provingKey *ProvingKeyFile) Pk() groth16.ProvingKey {
+ if provingKey.pk != nil {
+ return provingKey.pk
+ }
+
+ filePath := filePath(provingKey.FileID)
+ file, err := os.Open(filePath)
if err != nil {
- return nil, err
+ log.Errorf("couldn't open proving key file %s: %s", filePath, err)
+ return nil
}
- err = encoder.Close()
+ pk := groth16.NewProvingKey(ecc.BLS12_381)
+ _, err = pk.ReadFrom(file)
if err != nil {
- return nil, err
+ log.Errorf("couldn't read proving key file %s: %s", filePath, err)
+ return nil
}
- return append([]byte{'"'}, append(buf.Bytes(), '"')...), nil
+
+ provingKey.pk = pk
+ return pk
}
-type MarshallableVerifyingKey struct {
- Vk groth16.VerifyingKey
+type VerifyingKeyFile struct {
+ FileID string `json:"file_id"`
+ vk groth16.VerifyingKey `json:"-"`
}
-func (t *MarshallableVerifyingKey) UnmarshalJSON(b []byte) error {
- var buf bytes.Buffer
- _, err := buf.Write(bytes.Trim(b, "\""))
+func NewVerifyingKeyFile(vk groth16.VerifyingKey) *VerifyingKeyFile {
+ fileID := appservice.RandomString(24)
+ filePath := filePath(fileID)
+ file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Errorf("couldn't open file %s; this verifying key will be discarded upon exit: %s", filePath, err)
+ return &VerifyingKeyFile{"", vk}
+ }
+ _, err = vk.WriteTo(file)
if err != nil {
- return err
+ log.Errorf("couldn't write verifying key to file %s; this proving will be discarded upon exit: %s", filePath, err)
+ return &VerifyingKeyFile{"", vk}
+ }
+ return &VerifyingKeyFile{
+ FileID: fileID,
+ vk: vk,
}
- t.Vk = groth16.NewVerifyingKey(ecc.BLS12_381)
- _, err = t.Vk.ReadFrom(base64.NewDecoder(base64.StdEncoding, &buf))
- return err
}
-func (t *MarshallableVerifyingKey) MarshalJSON() ([]byte, error) {
- var buf bytes.Buffer
- encoder := base64.NewEncoder(base64.StdEncoding, &buf)
- _, err := t.Vk.WriteRawTo(encoder)
+func (verifyingKey *VerifyingKeyFile) Vk() groth16.VerifyingKey {
+ if verifyingKey.vk != nil {
+ return verifyingKey.vk
+ }
+
+ filePath := filePath(verifyingKey.FileID)
+ file, err := os.Open(filePath)
if err != nil {
- return nil, err
+ log.Errorf("couldn't open verifying key file %s: %s", filePath, err)
+ return nil
}
- err = encoder.Close()
+ vk := groth16.NewVerifyingKey(ecc.BLS12_381)
+ _, err = vk.ReadFrom(file)
if err != nil {
- return nil, err
+ log.Errorf("couldn't read verifying key file %s: %s", filePath, err)
+ return nil
}
- return append([]byte{'"'}, append(buf.Bytes(), '"')...), nil
+
+ verifyingKey.vk = vk
+ return vk
}
M election/marshal_test.go => election/marshal_test.go +8 -8
@@ 122,9 122,9 @@ func randomLocalVoter(t *testing.T) *LocalVoter {
}
// EvalProvingKey
- localVoter.EvalProvingKey = &MarshallableProvingKey{evalProvingKey}
+ localVoter.EvalProvingKey = NewProvingKeyFile("a", evalProvingKey)
// EvalVerifyingKey
- localVoter.EvalVerifyingKey = &MarshallableVerifyingKey{evalVerifyingKey}
+ localVoter.EvalVerifyingKey = NewVerifyingKeyFile(evalVerifyingKey)
}
{
@@ 137,9 137,9 @@ func randomLocalVoter(t *testing.T) *LocalVoter {
t.Fatal(err)
}
// SumProvingKey
- localVoter.SumProvingKey = &MarshallableProvingKey{sumProvingKey}
+ localVoter.SumProvingKey = NewProvingKeyFile("b", sumProvingKey)
// SumVerifyingKey
- localVoter.SumVerifyingKey = &MarshallableVerifyingKey{sumVerifyingKey}
+ localVoter.SumVerifyingKey = NewVerifyingKeyFile(sumVerifyingKey)
}
ballot := make([][]byte, numCandidates)
@@ 226,19 226,19 @@ func ensureEqual(t *testing.T, lv1 *LocalVoter, lv2 *LocalVoter) {
}
// EvalProvingKey
- if lv2.EvalProvingKey.Pk.IsDifferent(lv1.EvalProvingKey.Pk) {
+ if lv2.EvalProvingKey.Pk().IsDifferent(lv1.EvalProvingKey.Pk()) {
t.Error("eval proving keys not equal")
}
// EvalVerifyingKey
- if lv2.EvalVerifyingKey.Vk.IsDifferent(lv1.EvalVerifyingKey.Vk) {
+ if lv2.EvalVerifyingKey.Vk().IsDifferent(lv1.EvalVerifyingKey.Vk()) {
t.Error("eval verifying keys not equal")
}
// SumProvingKey
- if lv2.SumProvingKey.Pk.IsDifferent(lv1.SumProvingKey.Pk) {
+ if lv2.SumProvingKey.Pk().IsDifferent(lv1.SumProvingKey.Pk()) {
t.Error("sum proving keys not equal")
}
// SumVerifyingKey
- if lv2.SumVerifyingKey.Vk.IsDifferent(lv1.SumVerifyingKey.Vk) {
+ if lv2.SumVerifyingKey.Vk().IsDifferent(lv1.SumVerifyingKey.Vk()) {
t.Error("sum verifying keys not equal")
}
}
M election/msg.go => election/msg.go +18 -27
@@ 499,47 499,38 @@ func (elections *ElectionsMap) onKeysMessage(evt *event.Event, client *mautrix.C
return
}
- var evalProvingKey groth16.ProvingKey
+ var evalProvingKey *ProvingKeyFile
{
- // yes, I know we should be using Download here
- byts, err := client.DownloadBytes(content.EvalProvingKeyURI)
+ readCloser, err := client.Download(content.EvalProvingKeyURI)
if err != nil {
errorf("couldn't download eval proving key: %s", err)
return
}
- var buf bytes.Buffer
- _, err = buf.Write(byts)
- if err != nil {
- errorf("couldn't write to eval bytes buffer: %s")
- return
- }
- evalProvingKey = groth16.NewProvingKey(ecc.BLS12_381)
- _, err = evalProvingKey.ReadFrom(&buf)
+ pk := groth16.NewProvingKey(ecc.BLS12_381)
+ _, err = pk.ReadFrom(readCloser)
+ readCloser.Close()
if err != nil {
- errorf("couldn't read eval key from downloaded eval proving keys file: %s", err)
+ errorf("couldn't read eval proving key: %s", err)
return
}
+ evalProvingKey = NewProvingKeyFile(content.EvalProvingKeyURI.FileID, pk)
}
- var sumProvingKey groth16.ProvingKey
+ var sumProvingKey *ProvingKeyFile
{
- byts, err := client.DownloadBytes(content.SumProvingKeyURI)
+ readCloser, err := client.Download(content.SumProvingKeyURI)
if err != nil {
errorf("couldn't download sum proving key: %s", err)
return
}
- var buf bytes.Buffer
- _, err = buf.Write(byts)
- if err != nil {
- errorf("couldn't write to sum bytes buffer: %s")
- return
- }
- sumProvingKey = groth16.NewProvingKey(ecc.BLS12_381)
- _, err = sumProvingKey.ReadFrom(&buf)
+ pk := groth16.NewProvingKey(ecc.BLS12_381)
+ _, err = pk.ReadFrom(readCloser)
+ readCloser.Close()
if err != nil {
- errorf("couldn't read sum key from downloaded sum keys file: %s", err)
+ errorf("couldn't read sum proving key: %s", err)
return
}
+ sumProvingKey = NewProvingKeyFile(content.SumProvingKeyURI.FileID, pk)
}
var voter *Voter
@@ 565,8 556,8 @@ func (elections *ElectionsMap) onKeysMessage(evt *event.Event, client *mautrix.C
defer el.Save()
defer el.Unlock()
- voter.EvalProvingKey = &MarshallableProvingKey{evalProvingKey}
- voter.SumProvingKey = &MarshallableProvingKey{sumProvingKey}
+ voter.EvalProvingKey = evalProvingKey
+ voter.SumProvingKey = sumProvingKey
voter.KeysID = &evt.ID
return true
@@ 749,7 740,7 @@ func (elections *ElectionsMap) onEvalsMessage(evt *event.Event) (success bool) {
errorf("our evals verifying key is nil")
return
}
- err := groth16.Verify(proof, el.LocalVoter.EvalVerifyingKey.Vk, &publicCircuit)
+ err := groth16.Verify(proof, el.LocalVoter.EvalVerifyingKey.Vk(), &publicCircuit)
if err != nil {
warnf("poly eval proof verification failed: %s", err)
return
@@ 946,7 937,7 @@ func (elections *ElectionsMap) onSumMessage(evt *event.Event) (success bool) {
errorf("our sum verifying key is nil")
return
}
- err := groth16.Verify(proof, el.LocalVoter.SumVerifyingKey.Vk, &publicCircuit)
+ err := groth16.Verify(proof, el.LocalVoter.SumVerifyingKey.Vk(), &publicCircuit)
if err != nil {
warnf("sum proof verification failed: %s", err)
return
M election/voter.go => election/voter.go +9 -9
@@ 33,8 33,8 @@ type Voter struct {
Sum *fr.Element `json:"sum,omitempty"`
SumID *id.EventID `json:"sum_id,omitempty"`
- EvalProvingKey *MarshallableProvingKey `json:"eval_proving_key,omitempty"`
- SumProvingKey *MarshallableProvingKey `json:"sum_proving_key,omitempty"`
+ EvalProvingKey *ProvingKeyFile `json:"eval_proving_key,omitempty"`
+ SumProvingKey *ProvingKeyFile `json:"sum_proving_key,omitempty"`
}
type LocalVoter struct {
@@ 42,9 42,9 @@ type LocalVoter struct {
PrivKey [32]byte `json:"priv_key"`
- EvalVerifyingKey *MarshallableVerifyingKey `json:"eval_verifying_key,omitempty"`
- Poly *math.Poly `json:"poly,omitempty"`
- SumVerifyingKey *MarshallableVerifyingKey `json:"sum_verifying_key,omitempty"`
+ EvalVerifyingKey *VerifyingKeyFile `json:"eval_verifying_key,omitempty"`
+ Poly *math.Poly `json:"poly,omitempty"`
+ SumVerifyingKey *VerifyingKeyFile `json:"sum_verifying_key,omitempty"`
}
func NewVoter(input *fr.Element, joinEvt *event.Event, pubKey *[32]byte, seedPart []byte) *Voter {
@@ 286,8 286,8 @@ func (el *Election) SendProvingKeys(client *mautrix.Client, eventStore *EventSto
defer el.Save()
defer el.Unlock()
- el.LocalVoter.EvalVerifyingKey = &MarshallableVerifyingKey{evalVerifyingKey}
- el.LocalVoter.SumVerifyingKey = &MarshallableVerifyingKey{sumVerifyingKey}
+ el.LocalVoter.EvalVerifyingKey = NewVerifyingKeyFile(evalVerifyingKey)
+ el.LocalVoter.SumVerifyingKey = NewVerifyingKeyFile(sumVerifyingKey)
return nil
}
@@ 304,7 304,7 @@ func (el *Election) SendEvals(client *mautrix.Client, eventStore *EventStore) er
for i, joinID := range *el.FinalJoinIDs {
voter := el.Joins[joinID]
- output, outputHash, proof := el.LocalVoter.Poly.EvalAndProve(&voter.Input, voter.EvalProvingKey.Pk)
+ output, outputHash, proof := el.LocalVoter.Poly.EvalAndProve(&voter.Input, voter.EvalProvingKey.Pk())
// encrypt output
var outputBytes [32]byte
@@ 429,7 429,7 @@ func (el *Election) SendSum(client *mautrix.Client, eventStore *EventStore) erro
for i, joinID := range *el.FinalJoinIDs {
voter := *el.Joins[joinID]
- proof, err := groth16.Prove(r1cs, voter.SumProvingKey.Pk, &witness)
+ proof, err := groth16.Prove(r1cs, voter.SumProvingKey.Pk(), &witness)
if err != nil {
el.RUnlock()
return fmt.Errorf("couldn't prove sum: %s", err)
M go.sum => go.sum +4 -0
@@ 14,7 14,9 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo
github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt+M5idSED2YPGtwnfJV0kXohgdCBPmHGSYc1r04=
github.com/gdamore/tcell/v2 v2.4.1-0.20211227212015-3260e4ac4385 h1:O5oaOCRcXvNnsPikhB6xGd4a1bbfgcuFQCQgDB4tM7Y=
github.com/gdamore/tcell/v2 v2.4.1-0.20211227212015-3260e4ac4385/go.mod h1:I8YJFI9gzgl4dHi9UlRDZosCW+jYkDA37AXmXvL51w4=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ 98,10 100,12 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
maunium.net/go/mautrix v0.10.11 h1:u3D5+Ko7Pk0ruVFUAgjfk5E6U5Ys9VVObEGrytr0Hk4=
maunium.net/go/mautrix v0.10.11/go.mod h1:Ynac6y32yvdJC8YiYvWjWp6u1WjVTNq+JssC+07ZZWw=