// 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 import ( cryptorand ) 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 // Any methods implemented on PublicKey might need to also be implemented on // PrivateKey, as the latter embeds the former and will expose its methods. // Equal reports whether pub and x have the same value. func ( PublicKey) ( crypto.PublicKey) bool { , := .(PublicKey) if ! { return false } return bytes.Equal(, ) } // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. type PrivateKey []byte // Public returns the PublicKey corresponding to priv. func ( PrivateKey) () crypto.PublicKey { := make([]byte, PublicKeySize) copy(, [32:]) return PublicKey() } // Equal reports whether priv and x have the same value. func ( PrivateKey) ( crypto.PrivateKey) bool { , := .(PrivateKey) if ! { return false } return bytes.Equal(, ) } // 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 ( PrivateKey) () []byte { := make([]byte, SeedSize) copy(, [:32]) return } // 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 ( PrivateKey) ( io.Reader, []byte, crypto.SignerOpts) ( []byte, error) { if .HashFunc() != crypto.Hash(0) { return nil, errors.New("ed25519: cannot sign hashed message") } return Sign(, ), nil } // GenerateKey generates a public/private key pair using entropy from rand. // If rand is nil, crypto/rand.Reader will be used. func ( io.Reader) (PublicKey, PrivateKey, error) { if == nil { = cryptorand.Reader } := make([]byte, SeedSize) if , := io.ReadFull(, ); != nil { return nil, nil, } := NewKeyFromSeed() := make([]byte, PublicKeySize) copy(, [32:]) return , , 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 ( []byte) PrivateKey { // Outline the function body so that the returned key can be stack-allocated. := make([]byte, PrivateKeySize) newKeyFromSeed(, ) return } func newKeyFromSeed(, []byte) { if := len(); != SeedSize { panic("ed25519: bad seed length: " + strconv.Itoa()) } := sha512.Sum512() := edwards25519.NewScalar().SetBytesWithClamping([:32]) := (&edwards25519.Point{}).ScalarBaseMult() := .Bytes() copy(, ) copy([32:], ) } // Sign signs the message with privateKey and returns a signature. It will // panic if len(privateKey) is not PrivateKeySize. func ( PrivateKey, []byte) []byte { // Outline the function body so that the returned signature can be // stack-allocated. := make([]byte, SignatureSize) sign(, , ) return } func sign(, , []byte) { if := len(); != PrivateKeySize { panic("ed25519: bad private key length: " + strconv.Itoa()) } , := [:SeedSize], [SeedSize:] := sha512.Sum512() := edwards25519.NewScalar().SetBytesWithClamping([:32]) := [32:] := sha512.New() .Write() .Write() := make([]byte, 0, sha512.Size) = .Sum() := edwards25519.NewScalar().SetUniformBytes() := (&edwards25519.Point{}).ScalarBaseMult() := sha512.New() .Write(.Bytes()) .Write() .Write() := make([]byte, 0, sha512.Size) = .Sum() := edwards25519.NewScalar().SetUniformBytes() := edwards25519.NewScalar().MultiplyAdd(, , ) copy([:32], .Bytes()) copy([32:], .Bytes()) } // Verify reports whether sig is a valid signature of message by publicKey. It // will panic if len(publicKey) is not PublicKeySize. func ( PublicKey, , []byte) bool { if := len(); != PublicKeySize { panic("ed25519: bad public key length: " + strconv.Itoa()) } if len() != SignatureSize || [63]&224 != 0 { return false } , := (&edwards25519.Point{}).SetBytes() if != nil { return false } := sha512.New() .Write([:32]) .Write() .Write() := make([]byte, 0, sha512.Size) = .Sum() := edwards25519.NewScalar().SetUniformBytes() , := edwards25519.NewScalar().SetCanonicalBytes([32:]) if != nil { return false } // [S]B = R + [k]A --> [k](-A) + [S]B = R := (&edwards25519.Point{}).Negate() := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(, , ) return bytes.Equal([:32], .Bytes()) }