1
2
3
4
5
6
7
8
9
10
11
12
13 package ed25519
14
15 import (
16 "bytes"
17 "crypto"
18 "crypto/ed25519/internal/edwards25519"
19 cryptorand "crypto/rand"
20 "crypto/sha512"
21 "errors"
22 "io"
23 "strconv"
24 )
25
26 const (
27
28 PublicKeySize = 32
29
30 PrivateKeySize = 64
31
32 SignatureSize = 64
33
34 SeedSize = 32
35 )
36
37
38 type PublicKey []byte
39
40
41
42
43
44 func (pub PublicKey) Equal(x crypto.PublicKey) bool {
45 xx, ok := x.(PublicKey)
46 if !ok {
47 return false
48 }
49 return bytes.Equal(pub, xx)
50 }
51
52
53 type PrivateKey []byte
54
55
56 func (priv PrivateKey) Public() crypto.PublicKey {
57 publicKey := make([]byte, PublicKeySize)
58 copy(publicKey, priv[32:])
59 return PublicKey(publicKey)
60 }
61
62
63 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
64 xx, ok := x.(PrivateKey)
65 if !ok {
66 return false
67 }
68 return bytes.Equal(priv, xx)
69 }
70
71
72
73
74 func (priv PrivateKey) Seed() []byte {
75 seed := make([]byte, SeedSize)
76 copy(seed, priv[:32])
77 return seed
78 }
79
80
81
82
83
84
85 func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
86 if opts.HashFunc() != crypto.Hash(0) {
87 return nil, errors.New("ed25519: cannot sign hashed message")
88 }
89
90 return Sign(priv, message), nil
91 }
92
93
94
95 func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
96 if rand == nil {
97 rand = cryptorand.Reader
98 }
99
100 seed := make([]byte, SeedSize)
101 if _, err := io.ReadFull(rand, seed); err != nil {
102 return nil, nil, err
103 }
104
105 privateKey := NewKeyFromSeed(seed)
106 publicKey := make([]byte, PublicKeySize)
107 copy(publicKey, privateKey[32:])
108
109 return publicKey, privateKey, nil
110 }
111
112
113
114
115
116 func NewKeyFromSeed(seed []byte) PrivateKey {
117
118 privateKey := make([]byte, PrivateKeySize)
119 newKeyFromSeed(privateKey, seed)
120 return privateKey
121 }
122
123 func newKeyFromSeed(privateKey, seed []byte) {
124 if l := len(seed); l != SeedSize {
125 panic("ed25519: bad seed length: " + strconv.Itoa(l))
126 }
127
128 h := sha512.Sum512(seed)
129 s := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
130 A := (&edwards25519.Point{}).ScalarBaseMult(s)
131
132 publicKey := A.Bytes()
133
134 copy(privateKey, seed)
135 copy(privateKey[32:], publicKey)
136 }
137
138
139
140 func Sign(privateKey PrivateKey, message []byte) []byte {
141
142
143 signature := make([]byte, SignatureSize)
144 sign(signature, privateKey, message)
145 return signature
146 }
147
148 func sign(signature, privateKey, message []byte) {
149 if l := len(privateKey); l != PrivateKeySize {
150 panic("ed25519: bad private key length: " + strconv.Itoa(l))
151 }
152 seed, publicKey := privateKey[:SeedSize], privateKey[SeedSize:]
153
154 h := sha512.Sum512(seed)
155 s := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
156 prefix := h[32:]
157
158 mh := sha512.New()
159 mh.Write(prefix)
160 mh.Write(message)
161 messageDigest := make([]byte, 0, sha512.Size)
162 messageDigest = mh.Sum(messageDigest)
163 r := edwards25519.NewScalar().SetUniformBytes(messageDigest)
164
165 R := (&edwards25519.Point{}).ScalarBaseMult(r)
166
167 kh := sha512.New()
168 kh.Write(R.Bytes())
169 kh.Write(publicKey)
170 kh.Write(message)
171 hramDigest := make([]byte, 0, sha512.Size)
172 hramDigest = kh.Sum(hramDigest)
173 k := edwards25519.NewScalar().SetUniformBytes(hramDigest)
174
175 S := edwards25519.NewScalar().MultiplyAdd(k, s, r)
176
177 copy(signature[:32], R.Bytes())
178 copy(signature[32:], S.Bytes())
179 }
180
181
182
183 func Verify(publicKey PublicKey, message, sig []byte) bool {
184 if l := len(publicKey); l != PublicKeySize {
185 panic("ed25519: bad public key length: " + strconv.Itoa(l))
186 }
187
188 if len(sig) != SignatureSize || sig[63]&224 != 0 {
189 return false
190 }
191
192 A, err := (&edwards25519.Point{}).SetBytes(publicKey)
193 if err != nil {
194 return false
195 }
196
197 kh := sha512.New()
198 kh.Write(sig[:32])
199 kh.Write(publicKey)
200 kh.Write(message)
201 hramDigest := make([]byte, 0, sha512.Size)
202 hramDigest = kh.Sum(hramDigest)
203 k := edwards25519.NewScalar().SetUniformBytes(hramDigest)
204
205 S, err := edwards25519.NewScalar().SetCanonicalBytes(sig[32:])
206 if err != nil {
207 return false
208 }
209
210
211 minusA := (&edwards25519.Point{}).Negate(A)
212 R := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(k, minusA, S)
213
214 return bytes.Equal(sig[:32], R.Bytes())
215 }
216
View as plain text