From: Filippo Valsorda Date: Thu, 29 Dec 2022 12:08:48 +0000 (+0100) Subject: crypto/ed25519: improve Ed25519ctx docs and add example X-Git-Tag: go1.20~9^2~5 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=02ed0e5e67530e6b041989d55048ce373dc60327;p=gostls13.git crypto/ed25519: improve Ed25519ctx docs and add example Change-Id: Ic215a90d1e1daa5805dbab1dc56480281e53b341 Reviewed-on: https://go-review.googlesource.com/c/go/+/459975 Auto-Submit: Filippo Valsorda Run-TryBot: Filippo Valsorda Reviewed-by: Cherry Mui Reviewed-by: Roland Shoemaker TryBot-Result: Gopher Robot --- diff --git a/src/crypto/ed25519/ed25519.go b/src/crypto/ed25519/ed25519.go index 921bbaa8ed..a45d056851 100644 --- a/src/crypto/ed25519/ed25519.go +++ b/src/crypto/ed25519/ed25519.go @@ -49,10 +49,10 @@ func (pub PublicKey) Equal(x crypto.PublicKey) bool { return bytes.Equal(pub, xx) } -// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. +// PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer]. type PrivateKey []byte -// Public returns the PublicKey corresponding to priv. +// Public returns the [PublicKey] corresponding to priv. func (priv PrivateKey) Public() crypto.PublicKey { publicKey := make([]byte, PublicKeySize) copy(publicKey, priv[32:]) @@ -75,11 +75,15 @@ func (priv PrivateKey) Seed() []byte { return bytes.Clone(priv[:SeedSize]) } -// Sign signs the given message with priv. rand is ignored. 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 +// Sign signs the given message with priv. rand is ignored. +// +// 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 (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { hash := opts.HashFunc() context := "" @@ -108,7 +112,7 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp } } -// Options can be used with PrivateKey.Sign or VerifyWithOptions +// Options can be used with [PrivateKey.Sign] or [VerifyWithOptions] // to select Ed25519 variants. type Options struct { // Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph. @@ -119,10 +123,11 @@ type Options struct { Context string } +// HashFunc returns o.Hash. func (o *Options) HashFunc() crypto.Hash { return o.Hash } // GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. +// If rand is nil, [crypto/rand.Reader] will be used. func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { if rand == nil { rand = cryptorand.Reader @@ -141,7 +146,7 @@ func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { } // NewKeyFromSeed calculates a private key from a seed. It will panic if -// len(seed) is not SeedSize. This function is provided for interoperability +// 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 { @@ -170,7 +175,7 @@ func newKeyFromSeed(privateKey, seed []byte) { } // Sign signs the message with privateKey and returns a signature. It will -// panic if len(privateKey) is not PrivateKeySize. +// panic if len(privateKey) is not [PrivateKeySize]. func Sign(privateKey PrivateKey, message []byte) []byte { // Outline the function body so that the returned signature can be // stack-allocated. @@ -245,16 +250,18 @@ func sign(signature, privateKey, message []byte, domPrefix, context string) { } // Verify reports whether sig is a valid signature of message by publicKey. It -// will panic if len(publicKey) is not PublicKeySize. +// will panic if len(publicKey) is not [PublicKeySize]. func Verify(publicKey PublicKey, message, sig []byte) bool { return verify(publicKey, message, sig, domPrefixPure, "") } // VerifyWithOptions reports whether sig is a valid signature of message by -// publicKey. A valid signature is indicated by returning a nil error. -// 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 +// 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. func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error { switch { diff --git a/src/crypto/ed25519/ed25519_test.go b/src/crypto/ed25519/ed25519_test.go index ae5c872e02..47c8698e2a 100644 --- a/src/crypto/ed25519/ed25519_test.go +++ b/src/crypto/ed25519/ed25519_test.go @@ -14,11 +14,34 @@ import ( "crypto/sha512" "encoding/hex" "internal/testenv" + "log" "os" "strings" "testing" ) +func Example_ed25519ctx() { + pub, priv, err := GenerateKey(nil) + if err != nil { + log.Fatal(err) + } + + msg := []byte("The quick brown fox jumps over the lazy dog") + + sig, err := priv.Sign(nil, msg, &Options{ + Context: "Example_ed25519ctx", + }) + if err != nil { + log.Fatal(err) + } + + if err := VerifyWithOptions(pub, msg, sig, &Options{ + Context: "Example_ed25519ctx", + }); err != nil { + log.Fatal("invalid signature") + } +} + type zeroReader struct{} func (zeroReader) Read(buf []byte) (int, error) {