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