Home | History | Annotate | Download | only in ed25519
      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.
     10 package ed25519
     11 
     12 // This code is a port of the public domain, ref10 implementation of ed25519
     13 // from SUPERCOP.
     14 
     15 import (
     16 	"crypto"
     17 	cryptorand "crypto/rand"
     18 	"crypto/sha512"
     19 	"crypto/subtle"
     20 	"errors"
     21 	"io"
     22 	"strconv"
     23 
     24 	"./internal/edwards25519"
     25 )
     26 
     27 const (
     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.
     37 type PublicKey []byte
     38 
     39 // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
     40 type PrivateKey []byte
     41 
     42 // Public returns the PublicKey corresponding to priv.
     43 func (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.
     54 func (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.
     64 func 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.
     81 func 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.
    110 func 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.
    159 func 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