aboutsummaryrefslogtreecommitdiff
path: root/avnet/avnet.go
blob: e40759fe23857ada256613c52c39e40f6a709787 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
}