diff options
Diffstat (limited to 'vote/vote.go')
-rw-r--r-- | vote/vote.go | 223 |
1 files changed, 118 insertions, 105 deletions
diff --git a/vote/vote.go b/vote/vote.go index a97a66e..97367c0 100644 --- a/vote/vote.go +++ b/vote/vote.go @@ -1,60 +1,75 @@ package vote import ( + "bytes" "crypto/rand" "crypto/sha512" - "encoding/base32" - "encoding/binary" + "encoding/base64" + "encoding/json" "fmt" "io" curve "filippo.io/edwards25519" ) -var b32 = base32.StdEncoding.WithPadding(base32.NoPadding) +var b64 = base64.StdEncoding.WithPadding(base64.NoPadding) -// A Schnorr signature to prove knowledge of x for given g^x and i. - -type Proof struct { - PV curve.Point - Sr curve.Scalar - I uint64 -} - -type Commitment struct { - Index uint64 - Points struct { - X curve.Point - R curve.Point - } - Proofs struct { - X Proof - R Proof - } -} +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 { - X curve.Scalar - R curve.Scalar + id *scalar + x *scalar + r *scalar } Commitment } -func newPriv(s *curve.Scalar, random io.Reader) error { +// 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[:]) - _, e := s.SetUniformBytes(buf[:]) - return e + s, e := new(curve.Scalar).SetUniformBytes(buf[:]) + return (*scalar)(s), e } -func setPoint(p *curve.Scalar, P *curve.Point) *curve.Point { - return P.ScalarBaseMult(p) +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. @@ -64,75 +79,76 @@ func setPoint(p *curve.Scalar, P *curve.Point) *curve.Point { // 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 genProof(pr *Proof, x *curve.Scalar, i uint64) error { - pr.I = i - var v = new(curve.Scalar) - e := newPriv(v, nil) +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 e + return nil, e } - setPoint(v, &pr.PV) - gx := new(curve.Point) - setPoint(x, gx) - // Calculate h := H(g, g^v, g^x, i) - h, e := hash(&pr.PV, gx, i) + // 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 e + return nil, e } // Calculate r := v - x*h - xh := new(curve.Scalar).Multiply(x, h) - (&pr.Sr).Subtract(v, xh) + xh := new(curve.Scalar).Multiply((*curve.Scalar)(x), h) + r := new(curve.Scalar).Subtract((*curve.Scalar)(v), xh) + pr.Sr = (*scalar)(r) - return nil + return pr, nil } // Calculate h := H(g, g^v, g^x, i) -func hash(gv, gx *curve.Point, i uint64) (*curve.Scalar, error) { +func hash(gv, gx *point, id *point) (*curve.Scalar, error) { h512 := sha512.New() h512.Write(curve.NewGeneratorPoint().Bytes()) - h512.Write(gv.Bytes()) - h512.Write(gx.Bytes()) - _ = binary.Write(h512, binary.BigEndian, i) - + 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) { - e = genProof(&v.Proofs.X, &v.private.X, v.Index) + v.Proofs.X, e = v.private.x.proof(v.Id) if e != nil { return e } - return genProof(&v.Proofs.R, &v.private.R, v.Index) + v.Proofs.R, e = v.private.r.proof(v.Id) + return e } // Verifies that g^v == g^r*g^(x*h) -func verifyProof(V *curve.Point, r, x *curve.Scalar, i uint64) (ok bool) { - // Calculate h = H(g, g^v, g^x, i) - gx := new(curve.Point) - setPoint(x, gx) - h, e := hash(V, gx, i) +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) - xh := new(curve.Scalar).Multiply(x, h) - gxh := new(curve.Point) - setPoint(xh, gxh) + // Calculate g^(x*h) = (g^x)^h + gxh := new(curve.Point).ScalarMult(h, (*curve.Point)(Gx)) // Calculate g^r - gr := new(curve.Point) - setPoint(r, gr) + gr := r.point() // Calculate g^r*g^(x*h) // Note that the edwards25519 package uses Addtion as the group - grgxh := new(curve.Point).Add(gr, gxh) + grgxh := new(curve.Point).Add((*curve.Point)(gr), gxh) - return V.Equal(grgxh) == 1 + // Return true if g^v == g^r*g^(x*h) + return ((*curve.Point)(V)).Equal(grgxh) == 1 } func combineErr(e1, e2 error) error { @@ -147,74 +163,71 @@ func combineErr(e1, e2 error) error { return e2 } -// Verify checks for both, ProofX and ProofY that -// TODO +// Verify verifies the proofs for both, g^x and g^r func (v *Vote) VerifyProofs() (ok bool) { - okX := verifyProof(&v.Proofs.X.PV, &v.Proofs.X.Sr, &v.private.X, v.Index) - okR := verifyProof(&v.Proofs.R.PV, &v.Proofs.R.Sr, &v.private.R, v.Index) + 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 } -func newVoteWithRand(bit bool, index uint64, rand io.Reader) (vote *Vote, e error) { +// 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.Commitment.Index = index - e = newPriv(&vote.private.X, rand) + vote.private.id, e = randomScalar(rand) if e != nil { return nil, e } - e = newPriv(&vote.private.R, rand) + vote.private.x, e = randomScalar(rand) + if e != nil { + return nil, e + } + vote.private.r, e = randomScalar(rand) if e != nil { return nil, e } - setPoint(&vote.private.X, &vote.Commitment.Points.X) - setPoint(&vote.private.R, &vote.Commitment.Points.R) + 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 } -func NewVote(bit bool, index uint64) (vote *Vote, e error) { - return newVoteWithRand(bit, index, 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 ptStr(p *curve.Point) string { - return b32.EncodeToString(p.Bytes()) +func (s *scalar) String() string { + return b64.EncodeToString(((*curve.Scalar)(s)).Bytes()) } -func scStr(s *curve.Scalar) string { - return b32.EncodeToString(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 { - return fmt.Sprintf(`{ - "Index": %d, - "Points": { - "X": "%s", - "R": "%s" }, - "Proofs": { - "X": { - "PV": "%s", - "Sr": "%s" }, - "Y": { - "PV": "%s", - "Sr": "%s" } - } -}`, - c.Index, - ptStr(&c.Points.X), - ptStr(&c.Points.R), - ptStr(&c.Proofs.X.PV), - scStr(&c.Proofs.X.Sr), - ptStr(&c.Proofs.R.PV), - scStr(&c.Proofs.R.Sr)) -} - -func (c *Commitment) MarshalJSON() ([]byte, error) { - s := c.String() - return []byte(s), nil + 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() } |