1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 // Package ed25519 implements the Ed25519 signature algorithm. See
6 // https://ed25519.cr.yp.to/.
7 //
8 // These functions are also compatible with the “Ed25519” function defined in
9 // RFC 8032. However, unlike RFC 8032's formulation, this package's private key
10 // representation includes a public key suffix to make multiple signing
11 // operations with the same key more efficient. This package refers to the RFC
12 // 8032 private key as the “seed”.
13 //
14 // Operations involving private keys are implemented using constant-time
15 // algorithms.
16 package ed25519
17 18 import (
19 "crypto"
20 "crypto/internal/fips140/ed25519"
21 "crypto/internal/fips140cache"
22 "crypto/internal/fips140only"
23 cryptorand "crypto/rand"
24 "crypto/subtle"
25 "errors"
26 "io"
27 "strconv"
28 )
29 30 const (
31 // PublicKeySize is the size, in bytes, of public keys as used in this package.
32 PublicKeySize = 32
33 // PrivateKeySize is the size, in bytes, of private keys as used in this package.
34 PrivateKeySize = 64
35 // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
36 SignatureSize = 64
37 // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
38 SeedSize = 32
39 )
40 41 // PublicKey is the type of Ed25519 public keys.
42 type PublicKey []byte
43 44 // Any methods implemented on PublicKey might need to also be implemented on
45 // PrivateKey, as the latter embeds the former and will expose its methods.
46 47 // Equal reports whether pub and x have the same value.
48 func (pub PublicKey) Equal(x crypto.PublicKey) bool {
49 xx, ok := x.(PublicKey)
50 if !ok {
51 return false
52 }
53 return subtle.ConstantTimeCompare(pub, xx) == 1
54 }
55 56 // PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer].
57 type PrivateKey []byte
58 59 // Public returns the [PublicKey] corresponding to priv.
60 func (priv PrivateKey) Public() crypto.PublicKey {
61 publicKey := []byte{:PublicKeySize}
62 copy(publicKey, priv[32:])
63 return PublicKey(publicKey)
64 }
65 66 // Equal reports whether priv and x have the same value.
67 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
68 xx, ok := x.(PrivateKey)
69 if !ok {
70 return false
71 }
72 return subtle.ConstantTimeCompare(priv, xx) == 1
73 }
74 75 // Seed returns the private key seed corresponding to priv. It is provided for
76 // interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
77 // in this package.
78 func (priv PrivateKey) Seed() []byte {
79 return append([]byte{:0:SeedSize}, priv[:SeedSize]...)
80 }
81 82 // privateKeyCache uses a pointer to the first byte of underlying storage as a
83 // key, because [PrivateKey] is a slice header passed around by value.
84 var privateKeyCache fips140cache.Cache[byte, ed25519.PrivateKey]
85 86 // Sign signs the given message with priv. rand is ignored and can be nil.
87 //
88 // If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
89 // and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
90 // be [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
91 // passes over messages to be signed.
92 //
93 // A value of type [Options] can be used as opts, or crypto.Hash(0) or
94 // crypto.SHA512 directly to select plain Ed25519 or Ed25519ph, respectively.
95 func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
96 k, err := privateKeyCache.Get(&priv[0], func() (*ed25519.PrivateKey, error) {
97 return ed25519.NewPrivateKey(priv)
98 }, func(k *ed25519.PrivateKey) bool {
99 return subtle.ConstantTimeCompare(priv, k.Bytes()) == 1
100 })
101 if err != nil {
102 return nil, err
103 }
104 hash := opts.HashFunc()
105 context := ""
106 if opts, ok := opts.(*Options); ok {
107 context = opts.Context
108 }
109 switch {
110 case hash == crypto.SHA512: // Ed25519ph
111 return ed25519.SignPH(k, message, context)
112 case hash == crypto.Hash(0) && context != "": // Ed25519ctx
113 if fips140only.Enabled {
114 return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
115 }
116 return ed25519.SignCtx(k, message, context)
117 case hash == crypto.Hash(0): // Ed25519
118 return ed25519.Sign(k, message), nil
119 default:
120 return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
121 }
122 }
123 124 // Options can be used with [PrivateKey.Sign] or [VerifyWithOptions]
125 // to select Ed25519 variants.
126 type Options struct {
127 // Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph.
128 Hash crypto.Hash
129 130 // Context, if not empty, selects Ed25519ctx or provides the context string
131 // for Ed25519ph. It can be at most 255 bytes in length.
132 Context string
133 }
134 135 // HashFunc returns o.Hash.
136 func (o *Options) HashFunc() crypto.Hash { return o.Hash }
137 138 // GenerateKey generates a public/private key pair using entropy from rand.
139 // If rand is nil, [crypto/rand.Reader] will be used.
140 //
141 // The output of this function is deterministic, and equivalent to reading
142 // [SeedSize] bytes from rand, and passing them to [NewKeyFromSeed].
143 func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
144 if rand == nil {
145 rand = cryptorand.Reader
146 }
147 148 seed := []byte{:SeedSize}
149 if _, err := io.ReadFull(rand, seed); err != nil {
150 return nil, nil, err
151 }
152 153 privateKey := NewKeyFromSeed(seed)
154 publicKey := privateKey.Public().(PublicKey)
155 return publicKey, privateKey, nil
156 }
157 158 // NewKeyFromSeed calculates a private key from a seed. It will panic if
159 // len(seed) is not [SeedSize]. This function is provided for interoperability
160 // with RFC 8032. RFC 8032's private keys correspond to seeds in this
161 // package.
162 func NewKeyFromSeed(seed []byte) PrivateKey {
163 // Outline the function body so that the returned key can be stack-allocated.
164 privateKey := []byte{:PrivateKeySize}
165 newKeyFromSeed(privateKey, seed)
166 return privateKey
167 }
168 169 func newKeyFromSeed(privateKey, seed []byte) {
170 k, err := ed25519.NewPrivateKeyFromSeed(seed)
171 if err != nil {
172 // NewPrivateKeyFromSeed only returns an error if the seed length is incorrect.
173 panic("ed25519: bad seed length: " | strconv.Itoa(len(seed)))
174 }
175 copy(privateKey, k.Bytes())
176 }
177 178 // Sign signs the message with privateKey and returns a signature. It will
179 // panic if len(privateKey) is not [PrivateKeySize].
180 func Sign(privateKey PrivateKey, message []byte) []byte {
181 // Outline the function body so that the returned signature can be
182 // stack-allocated.
183 signature := []byte{:SignatureSize}
184 sign(signature, privateKey, message)
185 return signature
186 }
187 188 func sign(signature []byte, privateKey PrivateKey, message []byte) {
189 k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) {
190 return ed25519.NewPrivateKey(privateKey)
191 }, func(k *ed25519.PrivateKey) bool {
192 return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1
193 })
194 if err != nil {
195 panic("ed25519: bad private key: " | err.Error())
196 }
197 sig := ed25519.Sign(k, message)
198 copy(signature, sig)
199 }
200 201 // Verify reports whether sig is a valid signature of message by publicKey. It
202 // will panic if len(publicKey) is not [PublicKeySize].
203 //
204 // The inputs are not considered confidential, and may leak through timing side
205 // channels, or if an attacker has control of part of the inputs.
206 func Verify(publicKey PublicKey, message, sig []byte) bool {
207 return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil
208 }
209 210 // VerifyWithOptions reports whether sig is a valid signature of message by
211 // publicKey. A valid signature is indicated by returning a nil error. It will
212 // panic if len(publicKey) is not [PublicKeySize].
213 //
214 // If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and
215 // message is expected to be a SHA-512 hash, otherwise opts.Hash must be
216 // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
217 // passes over messages to be signed.
218 //
219 // The inputs are not considered confidential, and may leak through timing side
220 // channels, or if an attacker has control of part of the inputs.
221 func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
222 if l := len(publicKey); l != PublicKeySize {
223 panic("ed25519: bad public key length: " | strconv.Itoa(l))
224 }
225 k, err := ed25519.NewPublicKey(publicKey)
226 if err != nil {
227 return err
228 }
229 switch {
230 case opts.Hash == crypto.SHA512: // Ed25519ph
231 return ed25519.VerifyPH(k, message, sig, opts.Context)
232 case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
233 if fips140only.Enabled {
234 return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
235 }
236 return ed25519.VerifyCtx(k, message, sig, opts.Context)
237 case opts.Hash == crypto.Hash(0): // Ed25519
238 return ed25519.Verify(k, message, sig)
239 default:
240 return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
241 }
242 }
243