aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/ed25519
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ed25519')
-rw-r--r--vendor/golang.org/x/crypto/ed25519/ed25519.go60
-rw-r--r--vendor/golang.org/x/crypto/ed25519/ed25519_test.go37
-rw-r--r--vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go22
3 files changed, 107 insertions, 12 deletions
diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go
index 4f26b49..d6f683b 100644
--- a/vendor/golang.org/x/crypto/ed25519/ed25519.go
+++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go
@@ -6,7 +6,10 @@
// https://ed25519.cr.yp.to/.
//
// 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
// This code is a port of the public domain, “ref10” implementation of ed25519
@@ -31,6 +34,8 @@ const (
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.
@@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.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.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// 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.
// 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 {
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
}
- 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[31] &= 127
digest[31] |= 64
@@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
+ privateKey := make([]byte, PrivateKeySize)
+ copy(privateKey, seed)
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
@@ -171,9 +200,16 @@ func Verify(publicKey PublicKey, message, sig []byte) bool {
edwards25519.ScReduce(&hReduced, &digest)
var R edwards25519.ProjectiveGroupElement
- var b [32]byte
- copy(b[:], sig[32:])
- edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
+ var s [32]byte
+ copy(s[:], sig[32:])
+
+ // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
+ // the range [0, order) in order to prevent signature malleability.
+ if !edwards25519.ScMinimal(&s) {
+ return false
+ }
+
+ edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
var checkR [32]byte
R.ToBytes(&checkR)
diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
index e272f8a..8094603 100644
--- a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
+++ b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
@@ -139,6 +139,19 @@ func TestGolden(t *testing.T) {
if !Verify(pubKey, msg, sig2) {
t.Errorf("signature failed to verify on line %d", lineNo)
}
+
+ priv2 := NewKeyFromSeed(priv[:32])
+ if !bytes.Equal(priv[:], priv2) {
+ t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
+ }
+
+ if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
+ t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
+ }
+
+ if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
+ t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
+ }
}
if err := scanner.Err(); err != nil {
@@ -146,6 +159,30 @@ func TestGolden(t *testing.T) {
}
}
+func TestMalleability(t *testing.T) {
+ // https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
+ // that s be in [0, order). This prevents someone from adding a multiple of
+ // order to s and obtaining a second valid signature for the same message.
+ msg := []byte{0x54, 0x65, 0x73, 0x74}
+ sig := []byte{
+ 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
+ 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
+ 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
+ 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
+ 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
+ 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
+ }
+ publicKey := []byte{
+ 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
+ 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
+ 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
+ }
+
+ if Verify(publicKey, msg, sig) {
+ t.Fatal("non-canonical signature accepted")
+ }
+}
+
func BenchmarkKeyGeneration(b *testing.B) {
var zero zeroReader
for i := 0; i < b.N; i++ {
diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
index 5f8b994..fd03c25 100644
--- a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
+++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
@@ -4,6 +4,8 @@
package edwards25519
+import "encoding/binary"
+
// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.
@@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) {
out[30] = byte(s11 >> 9)
out[31] = byte(s11 >> 17)
}
+
+// order is the order of Curve25519 in little-endian form.
+var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000}
+
+// ScMinimal returns true if the given scalar is less than the order of the
+// curve.
+func ScMinimal(scalar *[32]byte) bool {
+ for i := 3; ; i-- {
+ v := binary.LittleEndian.Uint64(scalar[i*8:])
+ if v > order[i] {
+ return false
+ } else if v < order[i] {
+ break
+ } else if i == 0 {
+ return false
+ }
+ }
+
+ return true
+}