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