aboutsummaryrefslogtreecommitdiff
path: root/veto
diff options
context:
space:
mode:
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
commit989d09c8511eb10f2af06977d210deff39b6ff9e (patch)
treed360f2e3aa06d0e6dc2eaaac62274ca602d8821c /veto
parent458f9b7172148a272b23d61747f0758bf21dbf1f (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')
-rw-r--r--veto/veto.go183
-rw-r--r--veto/veto_test.go13
2 files changed, 61 insertions, 135 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
diff --git a/veto/veto_test.go b/veto/veto_test.go
index 847c7a0..a5f4fb2 100644
--- a/veto/veto_test.go
+++ b/veto/veto_test.go
@@ -3,6 +3,8 @@ package veto
import (
"math/rand"
"testing"
+
+ "kesim.org/seal/curve"
)
func TestVoteGeneration(t *testing.T) {
@@ -28,7 +30,7 @@ func TestRound2NoVeto(t *testing.T) {
var (
vs = []*Vote{}
cs = []*Commitment{}
- gcys = []*point{}
+ gcys = []*curve.Curve25519Point{}
num = 100
)
for i := range num {
@@ -63,7 +65,7 @@ func TestRound2WithVeto(t *testing.T) {
var (
vs = []*Vote{}
cs = []*Commitment{}
- gcys = []*point{}
+ gcys = []*curve.Curve25519Point{}
num = 100
index = int(rand.Int31n(int32(num)))
)
@@ -72,6 +74,9 @@ func TestRound2WithVeto(t *testing.T) {
if e != nil {
t.Fatalf("unexpected error: %v", e)
}
+ if vote.veto {
+ t.Logf("Veto for index no. %d\n", i)
+ }
com := vote.Commitment()
if !com.VerifyProofs() {
t.Fatalf("Proofs not correct for %d! %+v", i, com)
@@ -82,10 +87,10 @@ func TestRound2WithVeto(t *testing.T) {
for i := range num {
gcy, e := vs[i].Round2(cs)
- t.Logf("gcy: %v, e: %v", gcy, e)
if e != nil {
- t.Fatalf("Error calculating Round2: %v", e)
+ t.Fatalf("Error calculating Round2 for [%d]: %v", i, e)
}
+ t.Logf("gcy[%d]: %v", i, gcy)
gcys = append(gcys, gcy)
}