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