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:])
	for i := range seed {
		seed[i] = 0
	}
	return publicKey, privateKey, nil
}
GenerateKey generates a public/private key pair using entropy from rand.
If rand is nil, crypto/rand.Reader will be used.
package ed25519
import (
	"bytes"
	"crypto"
	cryptorand "crypto/rand"
	"crypto/sha512"
	"encoding/binary"
	"errors"
	"io"
	"strconv"
	"github.com/oasisprotocol/ed25519/internal/ge25519"
	"github.com/oasisprotocol/ed25519/internal/modm"
)
const (
	PublicKeySize = 32
	PrivateKeySize = 64
	SignatureSize = 64
	SeedSize = 32
	ContextMaxSize = 255
)
var _ crypto.Signer = (PrivateKey)(nil)
type Options struct {
	Hash crypto.Hash
	Context string
	ZIP215Verify bool
}
func (opt *Options) HashFunc() crypto.Hash {
	return opt.Hash
}
func (opt *Options) unwrap() (dom2Flag, []byte, error) {
	var (
		context []byte
		f       dom2Flag = fPure
	)
	if l := len(opt.Context); l > 0 {
		if l > ContextMaxSize {
			return f, nil, errors.New("ed25519: bad context length: " + strconv.Itoa(l))
		}
		context = []byte(opt.Context)
		f = fCtx
	}
	return f, context, nil
}
func checkHash(f dom2Flag, message []byte, hashFunc crypto.Hash) (dom2Flag, error) {
	switch hashFunc {
	case crypto.SHA512:
		if l := len(message); l != sha512.Size {
			return f, errors.New("ed25519: bad message hash length: " + strconv.Itoa(l))
		}
		f = fPh
	case crypto.Hash(0):
	default:
		return f, errors.New("ed25519: expected opts HashFunc zero (unhashed message, for Ed25519/Ed25519ctx) or SHA-512 (for Ed25519ph)")
	}
	return f, nil
}
type PrivateKey []byte
func (priv PrivateKey) Public() crypto.PublicKey {
	pub := make([]byte, PublicKeySize)
	copy(pub, priv[SeedSize:])
	return PublicKey(pub)
}
func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
	xx, ok := x.(PrivateKey)
	if !ok {
		return false
	}
	return bytes.Equal(priv, xx)
}
func (priv PrivateKey) Seed() []byte {
	s := make([]byte, SeedSize)
	copy(s, priv[:SeedSize])
	return s
}
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
	var (
		context []byte
		f       dom2Flag = fPure
	)
	if o, ok := opts.(*Options); ok {
		f, context, err = o.unwrap()
		if err != nil {
			return nil, err
		}
	}
	f, err = checkHash(f, message, opts.HashFunc())
	if err != nil {
		return nil, err
	}
	return sign(priv, message, f, context), nil
}
type PublicKey []byte
func (pub PublicKey) Equal(x crypto.PublicKey) bool {
	xx, ok := x.(PublicKey)
	if !ok {
		return false
	}
	return bytes.Equal(pub, xx)
}
func Sign(privateKey PrivateKey, message []byte) []byte {
	return sign(privateKey, message, fPure, nil)
}
func sign(privateKey PrivateKey, message []byte, f dom2Flag, c []byte) []byte {
	if l := len(privateKey); l != PrivateKeySize {
		panic("ed25519: bad private key length: " + strconv.Itoa(l))
	}
	var (
		extsk, hashr, hram [64]byte
		r, S, a            modm.Bignum256
		R                  ge25519.Ge25519
		RS [SignatureSize]byte
	)
	h := sha512.New()
	_, _ = h.Write(privateKey[:32])
	h.Sum(extsk[:0])
	extsk[0] &= 248
	extsk[31] &= 127
	extsk[31] |= 64
	h.Reset()
	if f != fPure {
		writeDom2(h, f, c)
	}
	_, _ = h.Write(extsk[32:])
	_, _ = h.Write(message)
	h.Sum(hashr[:0])
	modm.Expand(&r, hashr[:])
	ge25519.ScalarmultBaseNiels(&R, &ge25519.NielsBaseMultiples, &r)
	ge25519.Pack(RS[:], &R)
	h.Reset()
	if f != fPure {
		writeDom2(h, f, c)
	}
	_, _ = h.Write(RS[:32])
	_, _ = h.Write(privateKey[32:])
	_, _ = h.Write(message)
	h.Sum(hram[:0])
	modm.Expand(&S, hram[:])
	modm.Expand(&a, extsk[:32])
	modm.Mul(&S, &S, &a)
	modm.Add(&S, &S, &r)
	modm.Contract(RS[32:], &S)
	h.Reset()
	a.Reset()
	for i := range extsk {
		extsk[i] = 0
	}
	return RS[:]
}
func Verify(publicKey PublicKey, message, sig []byte) bool {
	return verify(publicKey, message, sig, fPure, nil, false)
}
func verify(publicKey PublicKey, message, sig []byte, f dom2Flag, c []byte, zip215 bool) bool {
	if l := len(publicKey); l != PublicKeySize {
		panic("ed25519: bad public key length: " + strconv.Itoa(l))
	}
	var (
		hash                [64]byte
		Rproj, R, A, checkR ge25519.Ge25519
		hram, S             modm.Bignum256
	)
	if len(sig) != SignatureSize || (sig[63]&224 != 0) || !ge25519.UnpackNegativeVartime(&A, publicKey) {
		return false
	}
	if !zip215 && isSmallOrderVartime(publicKey) {
		return false
	}
	h := sha512.New()
	if f != fPure {
		writeDom2(h, f, c)
	}
	_, _ = h.Write(sig[:32])
	_, _ = h.Write(publicKey[:])
	_, _ = h.Write(message)
	h.Sum(hash[:0])
	modm.Expand(&hram, hash[:])
	if !scMinimal(sig[32:]) {
		return false
	}
	if !ge25519.UnpackVartime(&checkR, sig[:32]) {
		return false
	}
	if !zip215 && isSmallOrderVartime(sig[:32]) {
		return false
	}
	modm.Expand(&S, sig[32:])
	ge25519.DoubleScalarmultVartime(&Rproj, &A, &hram, &S)
	ge25519.ProjectiveToExtended(&R, &Rproj)
	return ge25519.CofactorEqual(&R, &checkR)
}
func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) bool {
	ok, err := verifyWithOptionsNoPanic(publicKey, message, sig, opts)
	if err != nil {
		panic(err)
	}
	return ok
}
func verifyWithOptionsNoPanic(publicKey PublicKey, message, sig []byte, opts *Options) (bool, error) {
	f, context, err := opts.unwrap()
	if err != nil {
		return false, err
	}
	f, err = checkHash(f, message, opts.HashFunc())
	if err != nil {
		return false, err
	}
	if l := len(publicKey); l != PublicKeySize {
		return false, errors.New("ed25519: bad public key length: " + strconv.Itoa(l))
	}
	return verify(publicKey, message, sig, f, context, opts.ZIP215Verify), nil
}
func NewKeyFromSeed(seed []byte) PrivateKey {
	if l := len(seed); l != SeedSize {
		panic("ed25519: bad seed length: " + strconv.Itoa(l))
	}
	var digest [64]byte
	h := sha512.New()
	_, _ = h.Write(seed)
	h.Sum(digest[:0])
	h.Reset()
	digest[0] &= 248
	digest[31] &= 127
	digest[31] |= 64
	var (
		a              modm.Bignum256
		A              ge25519.Ge25519
		publicKeyBytes [32]byte
	)
	modm.Expand(&a, digest[:32])
	ge25519.ScalarmultBaseNiels(&A, &ge25519.NielsBaseMultiples, &a)
	ge25519.Pack(publicKeyBytes[:], &A)
	privateKey := make([]byte, PrivateKeySize)
	copy(privateKey, seed)
	copy(privateKey[32:], publicKeyBytes[:])
	for i := range digest {
		digest[i] = 0
	}
	a.Reset()
	return privateKey
}