You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
5.2 KiB

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