import (
"crypto"
"crypto/internal/fips/ed25519"
+ cryptorand "crypto/rand"
"crypto/subtle"
"errors"
"io"
// The output of this function is deterministic, and equivalent to reading
// [SeedSize] bytes from rand, and passing them to [NewKeyFromSeed].
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
- k, err := ed25519.GenerateKey(rand)
- if err != nil {
- return nil, nil, err
+ if rand == nil {
+ rand = cryptorand.Reader
}
- privateKey := make([]byte, PrivateKeySize)
- copy(privateKey, k.Bytes())
-
- publicKey := make([]byte, PublicKeySize)
- copy(publicKey, privateKey[32:])
+ seed := make([]byte, SeedSize)
+ if _, err := io.ReadFull(rand, seed); err != nil {
+ return nil, nil, err
+ }
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := privateKey.Public().(PublicKey)
return publicKey, privateKey, nil
}
}
}
+func TestGenerateKey(t *testing.T) {
+ // nil is like using crypto/rand.Reader.
+ public, private, err := GenerateKey(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(public) != PublicKeySize {
+ t.Errorf("public key has the wrong size: %d", len(public))
+ }
+ if len(private) != PrivateKeySize {
+ t.Errorf("private key has the wrong size: %d", len(private))
+ }
+ if !bytes.Equal(private.Public().(PublicKey), public) {
+ t.Errorf("public key doesn't match private key")
+ }
+ fromSeed := NewKeyFromSeed(private.Seed())
+ if !bytes.Equal(private, fromSeed) {
+ t.Errorf("recreating key pair from seed gave different private key")
+ }
+
+ _, k2, err := GenerateKey(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes.Equal(private, k2) {
+ t.Errorf("GenerateKey returned the same private key twice")
+ }
+
+ _, k3, err := GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes.Equal(private, k3) {
+ t.Errorf("GenerateKey returned the same private key twice")
+ }
+
+ // GenerateKey is documented to be the same as NewKeyFromSeed.
+ seed := make([]byte, SeedSize)
+ rand.Read(seed)
+ _, k4, err := GenerateKey(bytes.NewReader(seed))
+ if err != nil {
+ t.Fatal(err)
+ }
+ k4n := NewKeyFromSeed(seed)
+ if !bytes.Equal(k4, k4n) {
+ t.Errorf("GenerateKey with seed gave different private key")
+ }
+}
+
type zeroReader struct{}
func (zeroReader) Read(buf []byte) (int, error) {