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
}
|