|
@@ -6,7 +6,10 @@
|
|
|
// https://ed25519.cr.yp.to/.
|
|
// https://ed25519.cr.yp.to/.
|
|
|
//
|
|
//
|
|
|
// These functions are also compatible with the “Ed25519” function defined in
|
|
// These functions are also compatible with the “Ed25519” function defined in
|
|
|
-// RFC 8032.
|
|
|
|
|
|
|
+// 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
|
|
package ed25519
|
|
|
|
|
|
|
|
// This code is a port of the public domain, “ref10” implementation of ed25519
|
|
// This code is a port of the public domain, “ref10” implementation of ed25519
|
|
@@ -31,6 +34,8 @@ const (
|
|
|
PrivateKeySize = 64
|
|
PrivateKeySize = 64
|
|
|
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
|
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
|
|
SignatureSize = 64
|
|
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.
|
|
// PublicKey is the type of Ed25519 public keys.
|
|
@@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
|
|
|
return PublicKey(publicKey)
|
|
return PublicKey(publicKey)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 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 (priv PrivateKey) Seed() []byte {
|
|
|
|
|
+ seed := make([]byte, SeedSize)
|
|
|
|
|
+ copy(seed, priv[:32])
|
|
|
|
|
+ return seed
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// Sign signs the given message with priv.
|
|
// Sign signs the given message with priv.
|
|
|
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
|
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
|
|
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
|
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
|
@@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
|
|
|
|
|
|
|
|
// GenerateKey generates a public/private key pair using entropy from rand.
|
|
// 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 PublicKey, privateKey PrivateKey, err error) {
|
|
|
|
|
|
|
+func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
|
|
if rand == nil {
|
|
if rand == nil {
|
|
|
rand = cryptorand.Reader
|
|
rand = cryptorand.Reader
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- privateKey = make([]byte, PrivateKeySize)
|
|
|
|
|
- publicKey = make([]byte, PublicKeySize)
|
|
|
|
|
- _, err = io.ReadFull(rand, privateKey[:32])
|
|
|
|
|
- if err != nil {
|
|
|
|
|
|
|
+ seed := make([]byte, SeedSize)
|
|
|
|
|
+ if _, err := io.ReadFull(rand, seed); err != nil {
|
|
|
return nil, nil, err
|
|
return nil, nil, err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- digest := sha512.Sum512(privateKey[:32])
|
|
|
|
|
|
|
+ privateKey := NewKeyFromSeed(seed)
|
|
|
|
|
+ publicKey := make([]byte, PublicKeySize)
|
|
|
|
|
+ copy(publicKey, privateKey[32:])
|
|
|
|
|
+
|
|
|
|
|
+ return publicKey, privateKey, 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 NewKeyFromSeed(seed []byte) PrivateKey {
|
|
|
|
|
+ if l := len(seed); l != SeedSize {
|
|
|
|
|
+ panic("ed25519: bad seed length: " + strconv.Itoa(l))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ digest := sha512.Sum512(seed)
|
|
|
digest[0] &= 248
|
|
digest[0] &= 248
|
|
|
digest[31] &= 127
|
|
digest[31] &= 127
|
|
|
digest[31] |= 64
|
|
digest[31] |= 64
|
|
@@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
|
|
|
var publicKeyBytes [32]byte
|
|
var publicKeyBytes [32]byte
|
|
|
A.ToBytes(&publicKeyBytes)
|
|
A.ToBytes(&publicKeyBytes)
|
|
|
|
|
|
|
|
|
|
+ privateKey := make([]byte, PrivateKeySize)
|
|
|
|
|
+ copy(privateKey, seed)
|
|
|
copy(privateKey[32:], publicKeyBytes[:])
|
|
copy(privateKey[32:], publicKeyBytes[:])
|
|
|
- copy(publicKey, publicKeyBytes[:])
|
|
|
|
|
|
|
|
|
|
- return publicKey, privateKey, nil
|
|
|
|
|
|
|
+ return privateKey
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Sign signs the message with privateKey and returns a signature. It will
|
|
// Sign signs the message with privateKey and returns a signature. It will
|