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”. 13package ed25519 14 15// This code is a port of the public domain, “ref10” implementation of ed25519 16// from SUPERCOP. 17 18import ( 19 "bytes" 20 "crypto" 21 cryptorand "crypto/rand" 22 "crypto/sha512" 23 "errors" 24 "io" 25 "strconv" 26 27 "boringssl.googlesource.com/boringssl/ssl/test/runner/ed25519/internal/edwards25519" 28) 29 30const ( 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. 42type PublicKey []byte 43 44// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. 45type PrivateKey []byte 46 47// Public returns the PublicKey corresponding to priv. 48func (priv PrivateKey) Public() crypto.PublicKey { 49 publicKey := make([]byte, PublicKeySize) 50 copy(publicKey, priv[32:]) 51 return PublicKey(publicKey) 52} 53 54// Seed returns the private key seed corresponding to priv. It is provided for 55// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds 56// in this package. 57func (priv PrivateKey) Seed() []byte { 58 seed := make([]byte, SeedSize) 59 copy(seed, priv[:32]) 60 return seed 61} 62 63// Sign signs the given message with priv. 64// Ed25519 performs two passes over messages to be signed and therefore cannot 65// handle pre-hashed messages. Thus opts.HashFunc() must return zero to 66// indicate the message hasn't been hashed. This can be achieved by passing 67// crypto.Hash(0) as the value for opts. 68func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { 69 if opts.HashFunc() != crypto.Hash(0) { 70 return nil, errors.New("ed25519: cannot sign hashed message") 71 } 72 73 return Sign(priv, message), nil 74} 75 76// GenerateKey generates a public/private key pair using entropy from rand. 77// If rand is nil, crypto/rand.Reader will be used. 78func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { 79 if rand == nil { 80 rand = cryptorand.Reader 81 } 82 83 seed := make([]byte, SeedSize) 84 if _, err := io.ReadFull(rand, seed); err != nil { 85 return nil, nil, err 86 } 87 88 privateKey := NewKeyFromSeed(seed) 89 publicKey := make([]byte, PublicKeySize) 90 copy(publicKey, privateKey[32:]) 91 92 return publicKey, privateKey, nil 93} 94 95// NewKeyFromSeed calculates a private key from a seed. It will panic if 96// len(seed) is not SeedSize. This function is provided for interoperability 97// with RFC 8032. RFC 8032's private keys correspond to seeds in this 98// package. 99func NewKeyFromSeed(seed []byte) PrivateKey { 100 if l := len(seed); l != SeedSize { 101 panic("ed25519: bad seed length: " + strconv.Itoa(l)) 102 } 103 104 digest := sha512.Sum512(seed) 105 digest[0] &= 248 106 digest[31] &= 127 107 digest[31] |= 64 108 109 var A edwards25519.ExtendedGroupElement 110 var hBytes [32]byte 111 copy(hBytes[:], digest[:]) 112 edwards25519.GeScalarMultBase(&A, &hBytes) 113 var publicKeyBytes [32]byte 114 A.ToBytes(&publicKeyBytes) 115 116 privateKey := make([]byte, PrivateKeySize) 117 copy(privateKey, seed) 118 copy(privateKey[32:], publicKeyBytes[:]) 119 120 return privateKey 121} 122 123// Sign signs the message with privateKey and returns a signature. It will 124// panic if len(privateKey) is not PrivateKeySize. 125func Sign(privateKey PrivateKey, message []byte) []byte { 126 if l := len(privateKey); l != PrivateKeySize { 127 panic("ed25519: bad private key length: " + strconv.Itoa(l)) 128 } 129 130 h := sha512.New() 131 h.Write(privateKey[:32]) 132 133 var digest1, messageDigest, hramDigest [64]byte 134 var expandedSecretKey [32]byte 135 h.Sum(digest1[:0]) 136 copy(expandedSecretKey[:], digest1[:]) 137 expandedSecretKey[0] &= 248 138 expandedSecretKey[31] &= 63 139 expandedSecretKey[31] |= 64 140 141 h.Reset() 142 h.Write(digest1[32:]) 143 h.Write(message) 144 h.Sum(messageDigest[:0]) 145 146 var messageDigestReduced [32]byte 147 edwards25519.ScReduce(&messageDigestReduced, &messageDigest) 148 var R edwards25519.ExtendedGroupElement 149 edwards25519.GeScalarMultBase(&R, &messageDigestReduced) 150 151 var encodedR [32]byte 152 R.ToBytes(&encodedR) 153 154 h.Reset() 155 h.Write(encodedR[:]) 156 h.Write(privateKey[32:]) 157 h.Write(message) 158 h.Sum(hramDigest[:0]) 159 var hramDigestReduced [32]byte 160 edwards25519.ScReduce(&hramDigestReduced, &hramDigest) 161 162 var s [32]byte 163 edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) 164 165 signature := make([]byte, SignatureSize) 166 copy(signature[:], encodedR[:]) 167 copy(signature[32:], s[:]) 168 169 return signature 170} 171 172// Verify reports whether sig is a valid signature of message by publicKey. It 173// will panic if len(publicKey) is not PublicKeySize. 174func Verify(publicKey PublicKey, message, sig []byte) bool { 175 if l := len(publicKey); l != PublicKeySize { 176 panic("ed25519: bad public key length: " + strconv.Itoa(l)) 177 } 178 179 if len(sig) != SignatureSize || sig[63]&224 != 0 { 180 return false 181 } 182 183 var A edwards25519.ExtendedGroupElement 184 var publicKeyBytes [32]byte 185 copy(publicKeyBytes[:], publicKey) 186 if !A.FromBytes(&publicKeyBytes) { 187 return false 188 } 189 edwards25519.FeNeg(&A.X, &A.X) 190 edwards25519.FeNeg(&A.T, &A.T) 191 192 h := sha512.New() 193 h.Write(sig[:32]) 194 h.Write(publicKey[:]) 195 h.Write(message) 196 var digest [64]byte 197 h.Sum(digest[:0]) 198 199 var hReduced [32]byte 200 edwards25519.ScReduce(&hReduced, &digest) 201 202 var R edwards25519.ProjectiveGroupElement 203 var s [32]byte 204 copy(s[:], sig[32:]) 205 206 // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in 207 // the range [0, order) in order to prevent signature malleability. 208 if !edwards25519.ScMinimal(&s) { 209 return false 210 } 211 212 edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) 213 214 var checkR [32]byte 215 R.ToBytes(&checkR) 216 return bytes.Equal(sig[:32], checkR[:]) 217} 218