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