// 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”.//// Operations involving private keys are implemented using constant-time// algorithms.
package ed25519import (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.typePublicKey []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 ! {returnfalse }returnsubtle.ConstantTimeCompare(, ) == 1}// PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer].typePrivateKey []byte// Public returns the [PublicKey] corresponding to priv.func ( PrivateKey) () crypto.PublicKey { := make([]byte, PublicKeySize)copy(, [32:])returnPublicKey()}// Equal reports whether priv and x have the same value.func ( PrivateKey) ( crypto.PrivateKey) bool { , := .(PrivateKey)if ! {returnfalse }returnsubtle.ConstantTimeCompare(, ) == 1}// 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 {returnbytes.Clone([:SeedSize])}// Sign signs the given message with priv. rand is ignored and can be nil.//// If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used// and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must// be [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two// passes over messages to be signed.//// A value of type [Options] can be used as opts, or crypto.Hash(0) or// crypto.SHA512 directly to select plain Ed25519 or Ed25519ph, respectively.func ( PrivateKey) ( io.Reader, []byte, crypto.SignerOpts) ( []byte, error) { := .HashFunc() := ""if , := .(*Options); { = .Context }switch {case == crypto.SHA512: // Ed25519phif := len(); != sha512.Size {returnnil, errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa()) }if := len(); > 255 {returnnil, errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa()) } := make([]byte, SignatureSize)sign(, , , domPrefixPh, )return , nilcase == crypto.Hash(0) && != "": // Ed25519ctxif := len(); > 255 {returnnil, errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa()) } := make([]byte, SignatureSize)sign(, , , domPrefixCtx, )return , nilcase == crypto.Hash(0): // Ed25519returnSign(, ), nildefault:returnnil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)") }}// Options can be used with [PrivateKey.Sign] or [VerifyWithOptions]// to select Ed25519 variants.typeOptionsstruct {// Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph. Hash crypto.Hash// Context, if not empty, selects Ed25519ctx or provides the context string // for Ed25519ph. It can be at most 255 bytes in length. Context string}// HashFunc returns o.Hash.func ( *Options) () crypto.Hash { return .Hash }// GenerateKey generates a public/private key pair using entropy from rand.// If rand is nil, [crypto/rand.Reader] will be used.//// The output of this function is deterministic, and equivalent to reading// [SeedSize] bytes from rand, and passing them to [NewKeyFromSeed].func ( io.Reader) (PublicKey, PrivateKey, error) {if == nil { = cryptorand.Reader } := make([]byte, SeedSize)if , := io.ReadFull(, ); != nil {returnnil, 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])if != nil {panic("ed25519: internal error: setting scalar failed") } := (&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(, , , domPrefixPure, "")return}// Domain separation prefixes used to disambiguate Ed25519/Ed25519ph/Ed25519ctx.// See RFC 8032, Section 2 and Section 5.1.const (// domPrefixPure is empty for pure Ed25519. domPrefixPure = ""// domPrefixPh is dom2(phflag=1) for Ed25519ph. It must be followed by the // uint8-length prefixed context. domPrefixPh = "SigEd25519 no Ed25519 collisions\x01"// domPrefixCtx is dom2(phflag=0) for Ed25519ctx. It must be followed by the // uint8-length prefixed context. domPrefixCtx = "SigEd25519 no Ed25519 collisions\x00")func sign(, , []byte, , string) {if := len(); != PrivateKeySize {panic("ed25519: bad private key length: " + strconv.Itoa()) } , := [:SeedSize], [SeedSize:] := sha512.Sum512() , := edwards25519.NewScalar().SetBytesWithClamping([:32])if != nil {panic("ed25519: internal error: setting scalar failed") } := [32:] := sha512.New()if != domPrefixPure { .Write([]byte()) .Write([]byte{byte(len())}) .Write([]byte()) } .Write() .Write() := make([]byte, 0, sha512.Size) = .Sum() , := edwards25519.NewScalar().SetUniformBytes()if != nil {panic("ed25519: internal error: setting scalar failed") } := (&edwards25519.Point{}).ScalarBaseMult() := sha512.New()if != domPrefixPure { .Write([]byte()) .Write([]byte{byte(len())}) .Write([]byte()) } .Write(.Bytes()) .Write() .Write() := make([]byte, 0, sha512.Size) = .Sum() , := edwards25519.NewScalar().SetUniformBytes()if != nil {panic("ed25519: internal error: setting scalar failed") } := 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].//// The inputs are not considered confidential, and may leak through timing side// channels, or if an attacker has control of part of the inputs.func ( PublicKey, , []byte) bool {returnverify(, , , domPrefixPure, "")}// VerifyWithOptions reports whether sig is a valid signature of message by// publicKey. A valid signature is indicated by returning a nil error. It will// panic if len(publicKey) is not [PublicKeySize].//// If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and// message is expected to be a SHA-512 hash, otherwise opts.Hash must be// [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two// passes over messages to be signed.//// The inputs are not considered confidential, and may leak through timing side// channels, or if an attacker has control of part of the inputs.func ( PublicKey, , []byte, *Options) error {switch {case .Hash == crypto.SHA512: // Ed25519phif := len(); != sha512.Size {returnerrors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa()) }if := len(.Context); > 255 {returnerrors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa()) }if !verify(, , , domPrefixPh, .Context) {returnerrors.New("ed25519: invalid signature") }returnnilcase .Hash == crypto.Hash(0) && .Context != "": // Ed25519ctxif := len(.Context); > 255 {returnerrors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa()) }if !verify(, , , domPrefixCtx, .Context) {returnerrors.New("ed25519: invalid signature") }returnnilcase .Hash == crypto.Hash(0): // Ed25519if !verify(, , , domPrefixPure, "") {returnerrors.New("ed25519: invalid signature") }returnnildefault:returnerrors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)") }}func verify( PublicKey, , []byte, , string) bool {if := len(); != PublicKeySize {panic("ed25519: bad public key length: " + strconv.Itoa()) }iflen() != SignatureSize || [63]&224 != 0 {returnfalse } , := (&edwards25519.Point{}).SetBytes()if != nil {returnfalse } := sha512.New()if != domPrefixPure { .Write([]byte()) .Write([]byte{byte(len())}) .Write([]byte()) } .Write([:32]) .Write() .Write() := make([]byte, 0, sha512.Size) = .Sum() , := edwards25519.NewScalar().SetUniformBytes()if != nil {panic("ed25519: internal error: setting scalar failed") } , := edwards25519.NewScalar().SetCanonicalBytes([32:])if != nil {returnfalse }// [S]B = R + [k]A --> [k](-A) + [S]B = R := (&edwards25519.Point{}).Negate() := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(, , )returnbytes.Equal([:32], .Bytes())}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.