diff options
author | Özgür Kesim <oec@codeblau.de> | 2024-03-21 19:02:20 +0100 |
---|---|---|
committer | Özgür Kesim <oec@codeblau.de> | 2024-03-21 19:02:20 +0100 |
commit | 989d09c8511eb10f2af06977d210deff39b6ff9e (patch) | |
tree | d360f2e3aa06d0e6dc2eaaac62274ca602d8821c /veto/veto.go | |
parent | 458f9b7172148a272b23d61747f0758bf21dbf1f (diff) |
veto, curve: Added an abstraction layer for elliptic curves
This will allow to easily swap various curves and implementations, for benchmarking, f.e.
Diffstat (limited to 'veto/veto.go')
-rw-r--r-- | veto/veto.go | 183 |
1 files changed, 52 insertions, 131 deletions
diff --git a/veto/veto.go b/veto/veto.go index e59ec43..cb526d6 100644 --- a/veto/veto.go +++ b/veto/veto.go @@ -2,29 +2,25 @@ package veto import ( "bytes" - "crypto/rand" "crypto/sha512" - "encoding/base64" "encoding/json" "fmt" "io" "slices" - curve "filippo.io/edwards25519" + . "kesim.org/seal/curve" ) -var b64 = base64.StdEncoding.WithPadding(base64.NoPadding) +type Scalar = Curve25519Scalar +type Point = Curve25519Point -type point curve.Point -type scalar curve.Scalar - -// Representation of a vote with veto (true) +// Representation of a vote with veto (if set to true) type Vote struct { veto bool private struct { - id *scalar - x *scalar - r *scalar + id *Scalar + x *Scalar + r *Scalar } com *Commitment } @@ -32,10 +28,10 @@ type Vote struct { // Commitment represents the public data sent by a participant // in round 1 of the protocol. It is generated out of a Vote. type Commitment struct { - Id *point `json:"index"` + Id *Point `json:"identity"` Points struct { - X *point - R *point + X *Point + R *Point } `json:"points"` Proofs struct { X *Proof @@ -51,70 +47,9 @@ type Commitment struct { // // 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) -} - -func (p *point) Bytes() []byte { - return ((*curve.Point)(p)).Bytes() -} - -func one() *point { - return (*point)(curve.NewIdentityPoint()) -} - -type points []*point - -func (pts points) prod() (product *point) { - product = (*point)(curve.NewIdentityPoint()) - for _, p := range pts { - product = product.mult(p) - } - return product -} - -// Return p (*) q in group -func (p *point) mult(q *point) *point { - // The implementation in edwards25519 uses addition for the group operation. - r := new(curve.Point).Add((*curve.Point)(p), (*curve.Point)(q)) - return (*point)(r) -} - -// Return n*P , for n scalar, and P point -func (p *point) scalarMult(s *scalar) *point { - r := new(curve.Point).ScalarMult((*curve.Scalar)(s), (*curve.Point)(p)) - return (*point)(r) -} - -// Return p^(-1) -func (p *point) inv() *point { - n := new(curve.Point).Negate((*curve.Point)(p)) - return (*point)(n) -} - -func (s *scalar) Bytes() []byte { - return ((*curve.Scalar)(s)).Bytes() -} - -func (p *point) equal(q *point) bool { - return ((*curve.Point)(p)).Equal((*curve.Point)(q)) == 1 - + PV *Point `json:"V"` + Sr *Scalar `json:"r"` + Id *Point `json:"id"` } // Generates the proof, aka Schnorr signature, for given priv and i. @@ -124,20 +59,20 @@ func (p *point) equal(q *point) bool { // 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) { +func proof(x *Scalar, id *Point) (pr *Proof, e error) { pr = &Proof{Id: id} // choose random v - v, e := randomScalar(nil) + v, e := Curve25519.ScalarFromReader(nil) if e != nil { return nil, e } // calculate g^v - pr.PV = v.point() + pr.PV = Curve25519.Exp(v) // calculate g^x - gx := x.point() + gx := Curve25519.Exp(x) // calculate h := H(g, g^v, g^x, i) h, e := hash(pr.PV, gx, id) @@ -146,22 +81,22 @@ func (x *scalar) proof(id *point) (pr *Proof, e error) { } // 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) + xh := x.Mult(h) + r := v.Sub(xh) + pr.Sr = r return pr, nil } // Calculate h := H(g, g^v, g^x, i) -func hash(gv, gx *point, id *point) (*curve.Scalar, error) { +func hash(gv, gx *Point, id *Point) (*Scalar, error) { h512 := sha512.New() - h512.Write(curve.NewGeneratorPoint().Bytes()) + h512.Write(Curve25519.Identity().Bytes()) h512.Write(gv.Bytes()) h512.Write(gx.Bytes()) h512.Write(id.Bytes()) hb := h512.Sum(nil) - return new(curve.Scalar).SetUniformBytes(hb) + return Curve25519.ScalarFromBytes(hb) } func combineErr(es ...error) error { @@ -179,7 +114,7 @@ func combineErr(es ...error) error { } // Verifies that g^v == g^r*g^(x*h) -func verifyProof(V *point, Gx *point, r *scalar, id *point) (ok bool) { +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 { @@ -187,17 +122,17 @@ func verifyProof(V *point, Gx *point, r *scalar, id *point) (ok bool) { } // Calculate g^(x*h) = (g^x)^h - gxh := new(curve.Point).ScalarMult(h, (*curve.Point)(Gx)) + gxh := Gx.Exp(h) // Calculate g^r - gr := r.point() + gr := Curve25519.Exp(r) // Calculate g^r*g^(x*h) // Note that the edwards25519 package uses Addtion as the group - grgxh := gr.mult((*point)(gxh)) + grgxh := gr.Mult(gxh) // Return true if g^v == g^r*g^(x*h) - return V.equal(grgxh) + return V.Equal(grgxh) } // Verify verifies the proofs for both, g^x and g^r @@ -215,9 +150,9 @@ func newVoteWithRand(veto bool, rand io.Reader) (v *Vote, e error) { } var e1, e2, e3 error - v.private.id, e1 = randomScalar(rand) - v.private.x, e2 = randomScalar(rand) - v.private.r, e3 = randomScalar(rand) + v.private.id, e1 = Curve25519.ScalarFromReader(rand) + v.private.x, e2 = Curve25519.ScalarFromReader(rand) + v.private.r, e3 = Curve25519.ScalarFromReader(rand) e = combineErr(e1, e2, e3) if e != nil { @@ -226,11 +161,11 @@ func newVoteWithRand(veto bool, rand io.Reader) (v *Vote, e error) { c := new(Commitment) v.com = c - c.Id = v.private.id.point() - c.Points.X = v.private.x.point() - c.Points.R = v.private.r.point() - c.Proofs.X, e1 = v.private.x.proof(c.Id) - c.Proofs.R, e2 = v.private.r.proof(c.Id) + c.Id = Curve25519.Exp(v.private.id) + c.Points.X = Curve25519.Exp(v.private.x) + c.Points.R = Curve25519.Exp(v.private.r) + c.Proofs.X, e1 = proof(v.private.x, c.Id) + c.Proofs.R, e2 = proof(v.private.r, c.Id) return v, combineErr(e1, e2) } @@ -246,22 +181,6 @@ func (v *Vote) Commitment() *Commitment { return v.com } -func (p *point) String() string { - return b64.EncodeToString(p.Bytes()) -} - -func (s *scalar) String() string { - return b64.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 { buf := &bytes.Buffer{} dec := json.NewEncoder(buf) @@ -275,29 +194,29 @@ func (c *Commitment) String() string { type coms []*Commitment -func (coms coms) prod() (product *point) { - product = (*point)(curve.NewIdentityPoint()) +func (coms coms) prod() (product *Point) { + product = Curve25519.Identity() for _, com := range coms { - product = product.mult(com.Points.X) + product = product.Mult(com.Points.X) } return product } // For a given slice of commitments of length n, compute // g^y_i = Prod(g^x_j, 1, i-1)/Prod(g^x_j, i+1, n) -func (coms coms) computeGy(index int) *point { +func (coms coms) computeGy(index int) *Point { gy1 := coms[:index].prod() - gy2 := coms[index+1:].prod().inv() - return gy1.mult(gy2) + gy2 := coms[index+1:].prod().Inv() + return gy1.Mult(gy2) } // Round2 implements the round 2 of the AV-Net protocol, where a participant // has received all commitments from the other participants and calculates // g^(c*y), where c is either private.r (when veto is true) or private.x. -func (v *Vote) Round2(participants []*Commitment) (gcy *point, e error) { +func (v *Vote) Round2(participants []*Commitment) (gcy *Point, e error) { var c int for _, p := range participants { - if p.Id.equal(v.com.Id) { + if p.Id.Equal(v.com.Id) { c += 1 } } @@ -311,7 +230,7 @@ func (v *Vote) Round2(participants []*Commitment) (gcy *point, e error) { return bytes.Compare(a.Id.Bytes(), b.Id.Bytes()) }) - index := slices.IndexFunc(participants, func(c *Commitment) bool { return c.Id.equal(v.com.Id) }) + index := slices.IndexFunc(participants, func(c *Commitment) bool { return c.Id.Equal(v.com.Id) }) if index < 0 { // Should not happen! return nil, fmt.Errorf("Wait, what!? Couldn't find /me(%s) after sorting!", v.com.Id) @@ -319,16 +238,18 @@ func (v *Vote) Round2(participants []*Commitment) (gcy *point, e error) { gy := (coms(participants)).computeGy(index) if v.veto { - return gy.scalarMult(v.private.r), nil + return gy.Exp(v.private.r), nil } - return gy.scalarMult(v.private.x), nil + return gy.Exp(v.private.x), nil } +type points []*Point + // IsVetoed is the final step in the AV-Net protocol, where each participant, has // received the g^(c_i*y_i) from all other participants and calculates the product // of them. If the result is the unit element of the group, no veto was present. func (pts points) IsVetoed() bool { - product := pts.prod() - one := one() - return !one.equal(product) + product := Curve25519.Product(pts) + one := Curve25519.Identity() + return !one.Equal(product) }
\ No newline at end of file |