forked from dedis/kyber
/
eddsa.go
159 lines (131 loc) · 3.6 KB
/
eddsa.go
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Package eddsa implements the EdDSA signature algorithm according to
// RFC8032.
package eddsa
import (
"crypto/cipher"
"crypto/sha512"
"errors"
"fmt"
"github.com/michaljirman/kyber"
"github.com/michaljirman/kyber/group/edwards25519"
)
var group = new(edwards25519.Curve)
// EdDSA is a structure holding the data necessary to make a series of
// EdDSA signatures.
type EdDSA struct {
// Secret being already hashed + bit tweaked
Secret kyber.Scalar
// Public is the corresponding public key
Public kyber.Point
seed []byte
prefix []byte
}
// NewEdDSA will return a freshly generated key pair to use for generating
// EdDSA signatures.
func NewEdDSA(stream cipher.Stream) *EdDSA {
if stream == nil {
panic("stream is required")
}
secret, buffer, prefix := group.NewKeyAndSeed(stream)
public := group.Point().Mul(secret, nil)
return &EdDSA{
seed: buffer,
prefix: prefix,
Secret: secret,
Public: public,
}
}
// MarshalBinary will return the representation used by the reference
// implementation of SUPERCOP ref10, which is "seed || Public".
func (e *EdDSA) MarshalBinary() ([]byte, error) {
pBuff, err := e.Public.MarshalBinary()
if err != nil {
return nil, err
}
eddsa := make([]byte, 64)
copy(eddsa, e.seed)
copy(eddsa[32:], pBuff)
return eddsa, nil
}
// UnmarshalBinary transforms a slice of bytes into a EdDSA signature.
func (e *EdDSA) UnmarshalBinary(buff []byte) error {
if len(buff) != 64 {
return errors.New("wrong length for decoding EdDSA private")
}
secret, _, prefix := group.NewKeyAndSeedWithInput(buff[:32])
e.seed = buff[:32]
e.prefix = prefix
e.Secret = secret
e.Public = group.Point().Mul(e.Secret, nil)
return nil
}
// Sign will return a EdDSA signature of the message msg using Ed25519.
func (e *EdDSA) Sign(msg []byte) ([]byte, error) {
hash := sha512.New()
_, _ = hash.Write(e.prefix)
_, _ = hash.Write(msg)
// deterministic random secret and its commit
r := group.Scalar().SetBytes(hash.Sum(nil))
R := group.Point().Mul(r, nil)
// challenge
// H( R || Public || Msg)
hash.Reset()
Rbuff, err := R.MarshalBinary()
if err != nil {
return nil, err
}
Abuff, err := e.Public.MarshalBinary()
if err != nil {
return nil, err
}
_, _ = hash.Write(Rbuff)
_, _ = hash.Write(Abuff)
_, _ = hash.Write(msg)
h := group.Scalar().SetBytes(hash.Sum(nil))
// response
// s = r + h * s
s := group.Scalar().Mul(e.Secret, h)
s.Add(r, s)
sBuff, err := s.MarshalBinary()
if err != nil {
return nil, err
}
// return R || s
var sig [64]byte
copy(sig[:], Rbuff)
copy(sig[32:], sBuff)
return sig[:], nil
}
// Verify uses a public key, a message and a signature. It will return nil if
// sig is a valid signature for msg created by key public, or an error otherwise.
func Verify(public kyber.Point, msg, sig []byte) error {
if len(sig) != 64 {
return fmt.Errorf("signature length invalid, expect 64 but got %v", len(sig))
}
R := group.Point()
if err := R.UnmarshalBinary(sig[:32]); err != nil {
return fmt.Errorf("got R invalid point: %s", err)
}
s := group.Scalar()
if err := s.UnmarshalBinary(sig[32:]); err != nil {
return fmt.Errorf("schnorr: s invalid scalar %s", err)
}
// reconstruct h = H(R || Public || Msg)
Pbuff, err := public.MarshalBinary()
if err != nil {
return err
}
hash := sha512.New()
_, _ = hash.Write(sig[:32])
_, _ = hash.Write(Pbuff)
_, _ = hash.Write(msg)
h := group.Scalar().SetBytes(hash.Sum(nil))
// reconstruct S == k*A + R
S := group.Point().Mul(s, nil)
hA := group.Point().Mul(h, public)
RhA := group.Point().Add(R, hA)
if !RhA.Equal(S) {
return errors.New("reconstructed S is not equal to signature")
}
return nil
}