diff options
Diffstat (limited to 'vote')
-rw-r--r-- | vote/vote.go | 233 | ||||
-rw-r--r-- | vote/vote_test.go | 25 |
2 files changed, 0 insertions, 258 deletions
diff --git a/vote/vote.go b/vote/vote.go deleted file mode 100644 index 97367c0..0000000 --- a/vote/vote.go +++ /dev/null @@ -1,233 +0,0 @@ -package vote - -import ( - "bytes" - "crypto/rand" - "crypto/sha512" - "encoding/base64" - "encoding/json" - "fmt" - "io" - - curve "filippo.io/edwards25519" -) - -var b64 = base64.StdEncoding.WithPadding(base64.NoPadding) - -type point curve.Point -type scalar curve.Scalar - -// Representation of a vote (true or false) of an individual. -// The .Commitment is sent as data for round1 of the protocol. -type Vote struct { - bit bool - private struct { - id *scalar - x *scalar - r *scalar - } - - Commitment -} - -// Commitment represents the public data sent by a participant -// in round 1 of the protocol. -type Commitment struct { - Id *point `json:"index"` - Points struct { - X *point - R *point - } `json:"points"` - Proofs struct { - X *Proof - R *Proof - } `json:"proofs"` -} - -// A Schnorr signature to prove knowledge of v for given g^v and i. -// Choosing a scalar v randomly, the signature consists of (V, r) with -// -// V := g^v, with randomly chosen v -// r := (v - x*h), with h := H(g, g^v, g^x, i), where i is given by the context. -// -// Verification of the signature is by comparing V =?= g^r * g^(x*h) -type Proof struct { - PV *point `json:"V"` - Sr *scalar `json:"r"` - Id *point `json:"id"` -} - -func randomScalar(random io.Reader) (*scalar, error) { - var buf [64]byte - if random == nil { - random = rand.Reader - } - random.Read(buf[:]) - s, e := new(curve.Scalar).SetUniformBytes(buf[:]) - return (*scalar)(s), e -} - -func (s *scalar) point() *point { - p := new(curve.Point).ScalarBaseMult((*curve.Scalar)(s)) - return (*point)(p) -} - -// Generates the proof, aka Schnorr signature, for given priv and i. -// Choosing a scalar v randomly, the signature consists of (V, r) with -// -// V := g^v, with randomly chosen v -// r := (v - x*h), with h := H(g, g^v, g^x, i), where i is given by the context. -// -// Verification of the signature is by comparing V =?= g^r * g^(x*h) -func (x *scalar) proof(id *point) (pr *Proof, e error) { - pr = &Proof{Id: id} - - // choose random v - v, e := randomScalar(nil) - if e != nil { - return nil, e - } - - // calculate g^v - pr.PV = v.point() - - // calculate g^x - gx := x.point() - - // calculate h := H(g, g^v, g^x, i) - h, e := hash(pr.PV, gx, id) - if e != nil { - return nil, e - } - - // Calculate r := v - x*h - xh := new(curve.Scalar).Multiply((*curve.Scalar)(x), h) - r := new(curve.Scalar).Subtract((*curve.Scalar)(v), xh) - pr.Sr = (*scalar)(r) - - return pr, nil -} - -// Calculate h := H(g, g^v, g^x, i) -func hash(gv, gx *point, id *point) (*curve.Scalar, error) { - h512 := sha512.New() - h512.Write(curve.NewGeneratorPoint().Bytes()) - h512.Write(((*curve.Point)(gv)).Bytes()) - h512.Write(((*curve.Point)(gx)).Bytes()) - h512.Write(((*curve.Point)(id)).Bytes()) - hb := h512.Sum(nil) - return new(curve.Scalar).SetUniformBytes(hb) -} - -// Generate the proofs for both, the g^x and g^r points. -func (v *Vote) genProofs() (e error) { - v.Proofs.X, e = v.private.x.proof(v.Id) - if e != nil { - return e - } - v.Proofs.R, e = v.private.r.proof(v.Id) - return e -} - -// Verifies that g^v == g^r*g^(x*h) -func verifyProof(V *point, Gx *point, r *scalar, id *point) (ok bool) { - // Calculate h = H(g, g^v, g^x, id) - h, e := hash(V, Gx, id) - if e != nil { - return false - } - - // Calculate g^(x*h) = (g^x)^h - gxh := new(curve.Point).ScalarMult(h, (*curve.Point)(Gx)) - - // Calculate g^r - gr := r.point() - - // Calculate g^r*g^(x*h) - // Note that the edwards25519 package uses Addtion as the group - grgxh := new(curve.Point).Add((*curve.Point)(gr), gxh) - - // Return true if g^v == g^r*g^(x*h) - return ((*curve.Point)(V)).Equal(grgxh) == 1 -} - -func combineErr(e1, e2 error) error { - if e1 == nil && e2 == nil { - return nil - } else if e1 != nil { - if e2 == nil { - return e1 - } - return fmt.Errorf("%v and %v", e1, e2) - } - return e2 -} - -// Verify verifies the proofs for both, g^x and g^r -func (v *Vote) VerifyProofs() (ok bool) { - okX := verifyProof(v.Proofs.X.PV, v.Points.X, v.Proofs.X.Sr, v.Id) - okR := verifyProof(v.Proofs.R.PV, v.Points.R, v.Proofs.R.Sr, v.Id) - return okX && okR -} - -// Generates a vote with commitments and proofs and takes the input for -// the randomness from the given io.Reader -func newVoteWithRand(bit bool, rand io.Reader) (vote *Vote, e error) { - vote = &Vote{ - bit: bit, - } - - vote.private.id, e = randomScalar(rand) - if e != nil { - return nil, e - } - vote.private.x, e = randomScalar(rand) - if e != nil { - return nil, e - } - vote.private.r, e = randomScalar(rand) - if e != nil { - return nil, e - } - - vote.Commitment.Id = vote.private.id.point() - vote.Commitment.Points.X = vote.private.x.point() - vote.Commitment.Points.R = vote.private.r.point() - - e = vote.genProofs() - - return vote, nil -} - -// NewVote generates a vote for given bit and index, taking crypt/Reader as -// source for randomness -func NewVote(bit bool) (vote *Vote, e error) { - return newVoteWithRand(bit, nil) -} - -func (p *point) String() string { - return b64.EncodeToString(((*curve.Point)(p)).Bytes()) -} - -func (s *scalar) String() string { - return b64.EncodeToString(((*curve.Scalar)(s)).Bytes()) -} - -func (s *scalar) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"%s"`, s)), nil - -} -func (p *point) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"%s"`, p)), nil -} - -func (c *Commitment) String() string { - buf := &bytes.Buffer{} - dec := json.NewEncoder(buf) - dec.SetIndent("", " ") - e := dec.Encode(c) - if e != nil { - return fmt.Sprintf("<error encoding: %v>", e) - } - return buf.String() -} diff --git a/vote/vote_test.go b/vote/vote_test.go deleted file mode 100644 index 437dbe5..0000000 --- a/vote/vote_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package vote - -import ( - "testing" -) - -func TestVoteGeneration(t *testing.T) { - - for i := range 100 { - bit := i%3 == 1 - vote, e := newVoteWithRand(bit, nil) - - if e != nil { - t.Fatalf("unexpected error: %v", e) - } - if vote.bit != bit { - t.Fatalf("expected vote %t, but got %t", bit, vote.bit) - } - if !vote.VerifyProofs() { - t.Fatalf("Proofs not correct! %+v", vote) - } - - t.Logf("Generated %s\n", vote) - } -} |