diff options
Diffstat (limited to 'avnet/avnet.go')
-rw-r--r-- | avnet/avnet.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/avnet/avnet.go b/avnet/avnet.go new file mode 100644 index 0000000..e40759f --- /dev/null +++ b/avnet/avnet.go @@ -0,0 +1,123 @@ +package avnet + +import ( + "crypto/rand" + "crypto/sha256" + "encoding/base32" + "encoding/binary" + "fmt" + "io" + + curve "filippo.io/edwards25519" +) + +var b32 = base32.StdEncoding.WithPadding(base32.NoPadding) + +// A Schnorr signature to prove knowledge of x for given g^x and i. + +type Proof struct { + PointV curve.Point + ScalarR curve.Scalar + I uint64 +} + +type Commitment struct { + PubX curve.Point + PubR curve.Point + ProofX Proof + ProofR Proof +} + +type Vote struct { + bit bool + + privX curve.Scalar + privR curve.Scalar + + Commitment +} + +func newPriv(s *curve.Scalar, random io.Reader) error { + var buf [64]byte + if random == nil { + random = rand.Reader + } + random.Read(buf[:]) + _, e := s.SetUniformBytes(buf[:]) + return e +} + +func setPub(p *curve.Scalar, P *curve.Point) *curve.Point { + return P.ScalarBaseMult(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 proof(pr *Proof, x *curve.Scalar, i uint64) error { + pr.I = i + var v curve.Scalar + e := newPriv(&v, nil) + if e != nil { + return e + } + setPub(&v, &pr.PointV) + gx := curve.Point{} + setPub(x, &gx) + + // Calculate h := H(g, g^v, g^x, i) + h256 := sha256.New() + h256.Write(curve.NewGeneratorPoint().Bytes()) + h256.Write(pr.PointV.Bytes()) + h256.Write(gx.Bytes()) + e = binary.Write(h256, binary.BigEndian, i) + if e != nil { + return e + } + // h := h256.Bytes() + + // TODO: calculate r + return fmt.Errorf("proof not implemented") + +} + +func newVoteWithRand(bit bool, rand io.Reader) (vote *Vote, e error) { + vote = &Vote{ + bit: bit, + } + + e = newPriv(&vote.privX, rand) + if e != nil { + return nil, e + } + e = newPriv(&vote.privR, rand) + if e != nil { + return nil, e + } + + setPub(&vote.privX, &vote.Commitment.PubX) + setPub(&vote.privR, &vote.Commitment.PubR) + + return vote, nil +} + +func NewVote(bit bool) (vote *Vote, e error) { + return newVoteWithRand(bit, nil) +} + +func pubStr(p *curve.Point) string { + return b32.EncodeToString(p.Bytes()) +} + +func (c *Commitment) String() string { + return fmt.Sprintf(`{"PubX": "%s", "PubR": "%s"}`, pubStr(&c.PubX), pubStr(&c.PubR)) +} + +func (c *Commitment) MarshalJSON() ([]byte, error) { + s := c.String() + return []byte(s), nil +}
\ No newline at end of file |