aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/golang.org/x/crypto/ed25519/ed25519.go
blob: d6f683ba3f788f3b1fcb07f79f1162be843142a8 (plain) (tree)
1
2
3
4
5
6
7
8




                                                                  
                             

                                                                                 



                                                                               





                                                                                  
               


                                













                                                                                                     

                                                                                                                            














                                                                               








                                                                              














                                                                                                                   
                                                                 



                                        

                                                          


                                    
















                                                                            










                                                  

                                                  
                                                
 
                         

















































































                                                                                                









                                                                                  


                           
                                               
 
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
package ed25519

// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.

import (
    "bytes"
    "crypto"
    cryptorand "crypto/rand"
    "crypto/sha512"
    "errors"
    "io"
    "strconv"

    "golang.org/x/crypto/ed25519/internal/edwards25519"
)

const (
    // PublicKeySize is the size, in bytes, of public keys as used in this package.
    PublicKeySize = 32
    // PrivateKeySize is the size, in bytes, of private keys as used in this package.
    PrivateKeySize = 64
    // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
    SignatureSize = 64
    // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
    SeedSize = 32
)

// PublicKey is the type of Ed25519 public keys.
type PublicKey []byte

// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
type PrivateKey []byte

// Public returns the PublicKey corresponding to priv.
func (priv PrivateKey) Public() crypto.PublicKey {
    publicKey := make([]byte, PublicKeySize)
    copy(publicKey, priv[32:])
    return PublicKey(publicKey)
}

// Seed returns the private key seed corresponding to priv. It is provided for
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
// in this package.
func (priv PrivateKey) Seed() []byte {
    seed := make([]byte, SeedSize)
    copy(seed, priv[:32])
    return seed
}

// Sign signs the given message with priv.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
// indicate the message hasn't been hashed. This can be achieved by passing
// crypto.Hash(0) as the value for opts.
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
    if opts.HashFunc() != crypto.Hash(0) {
        return nil, errors.New("ed25519: cannot sign hashed message")
    }

    return Sign(priv, message), nil
}

// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
    if rand == nil {
        rand = cryptorand.Reader
    }

    seed := make([]byte, SeedSize)
    if _, err := io.ReadFull(rand, seed); err != nil {
        return nil, nil, err
    }

    privateKey := NewKeyFromSeed(seed)
    publicKey := make([]byte, PublicKeySize)
    copy(publicKey, privateKey[32:])

    return publicKey, privateKey, nil
}

// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
    if l := len(seed); l != SeedSize {
        panic("ed25519: bad seed length: " + strconv.Itoa(l))
    }

    digest := sha512.Sum512(seed)
    digest[0] &= 248
    digest[31] &= 127
    digest[31] |= 64

    var A edwards25519.ExtendedGroupElement
    var hBytes [32]byte
    copy(hBytes[:], digest[:])
    edwards25519.GeScalarMultBase(&A, &hBytes)
    var publicKeyBytes [32]byte
    A.ToBytes(&publicKeyBytes)

    privateKey := make([]byte, PrivateKeySize)
    copy(privateKey, seed)
    copy(privateKey[32:], publicKeyBytes[:])

    return privateKey
}

// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
    if l := len(privateKey); l != PrivateKeySize {
        panic("ed25519: bad private key length: " + strconv.Itoa(l))
    }

    h := sha512.New()
    h.Write(privateKey[:32])

    var digest1, messageDigest, hramDigest [64]byte
    var expandedSecretKey [32]byte
    h.Sum(digest1[:0])
    copy(expandedSecretKey[:], digest1[:])
    expandedSecretKey[0] &= 248
    expandedSecretKey[31] &= 63
    expandedSecretKey[31] |= 64

    h.Reset()
    h.Write(digest1[32:])
    h.Write(message)
    h.Sum(messageDigest[:0])

    var messageDigestReduced [32]byte
    edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
    var R edwards25519.ExtendedGroupElement
    edwards25519.GeScalarMultBase(&R, &messageDigestReduced)

    var encodedR [32]byte
    R.ToBytes(&encodedR)

    h.Reset()
    h.Write(encodedR[:])
    h.Write(privateKey[32:])
    h.Write(message)
    h.Sum(hramDigest[:0])
    var hramDigestReduced [32]byte
    edwards25519.ScReduce(&hramDigestReduced, &hramDigest)

    var s [32]byte
    edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)

    signature := make([]byte, SignatureSize)
    copy(signature[:], encodedR[:])
    copy(signature[32:], s[:])

    return signature
}

// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
    if l := len(publicKey); l != PublicKeySize {
        panic("ed25519: bad public key length: " + strconv.Itoa(l))
    }

    if len(sig) != SignatureSize || sig[63]&224 != 0 {
        return false
    }

    var A edwards25519.ExtendedGroupElement
    var publicKeyBytes [32]byte
    copy(publicKeyBytes[:], publicKey)
    if !A.FromBytes(&publicKeyBytes) {
        return false
    }
    edwards25519.FeNeg(&A.X, &A.X)
    edwards25519.FeNeg(&A.T, &A.T)

    h := sha512.New()
    h.Write(sig[:32])
    h.Write(publicKey[:])
    h.Write(message)
    var digest [64]byte
    h.Sum(digest[:0])

    var hReduced [32]byte
    edwards25519.ScReduce(&hReduced, &digest)

    var R edwards25519.ProjectiveGroupElement
    var s [32]byte
    copy(s[:], sig[32:])

    // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
    // the range [0, order) in order to prevent signature malleability.
    if !edwards25519.ScMinimal(&s) {
        return false
    }

    edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)

    var checkR [32]byte
    R.ToBytes(&checkR)
    return bytes.Equal(sig[:32], checkR[:])
}