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// In Go 1.13, the ed25519 package was promoted to the standard library as
6// crypto/ed25519, and this package became a wrapper for the standard library one.
7//
8//go:build !go1.13
9// +build !go1.13
10
11// Package ed25519 implements the Ed25519 signature algorithm. See
12// https://ed25519.cr.yp.to/.
13//
14// These functions are also compatible with the “Ed25519” function defined in
15// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
16// representation includes a public key suffix to make multiple signing
17// operations with the same key more efficient. This package refers to the RFC
18// 8032 private key as the “seed”.
19package ed25519
20
21// This code is a port of the public domain, “ref10” implementation of ed25519
22// from SUPERCOP.
23
24import (
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
36const (
37	// PublicKeySize is the size, in bytes, of public keys as used in this package.
38	PublicKeySize = 32
39	// PrivateKeySize is the size, in bytes, of private keys as used in this package.
40	PrivateKeySize = 64
41	// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
42	SignatureSize = 64
43	// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
44	SeedSize = 32
45)
46
47// PublicKey is the type of Ed25519 public keys.
48type PublicKey []byte
49
50// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
51type PrivateKey []byte
52
53// Public returns the PublicKey corresponding to priv.
54func (priv PrivateKey) Public() crypto.PublicKey {
55	publicKey := make([]byte, PublicKeySize)
56	copy(publicKey, priv[32:])
57	return PublicKey(publicKey)
58}
59
60// Seed returns the private key seed corresponding to priv. It is provided for
61// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
62// in this package.
63func (priv PrivateKey) Seed() []byte {
64	seed := make([]byte, SeedSize)
65	copy(seed, priv[:32])
66	return seed
67}
68
69// Sign signs the given message with priv.
70// Ed25519 performs two passes over messages to be signed and therefore cannot
71// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
72// indicate the message hasn't been hashed. This can be achieved by passing
73// crypto.Hash(0) as the value for opts.
74func (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// GenerateKey generates a public/private key pair using entropy from rand.
83// If rand is nil, crypto/rand.Reader will be used.
84func 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// NewKeyFromSeed calculates a private key from a seed. It will panic if
102// len(seed) is not SeedSize. This function is provided for interoperability
103// with RFC 8032. RFC 8032's private keys correspond to seeds in this
104// package.
105func 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// Sign signs the message with privateKey and returns a signature. It will
130// panic if len(privateKey) is not PrivateKeySize.
131func 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// Verify reports whether sig is a valid signature of message by publicKey. It
179// will panic if len(publicKey) is not PublicKeySize.
180func 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	// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
213	// the range [0, order) in order to prevent signature malleability.
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