summaryrefslogtreecommitdiffstats
path: root/src/crypto/ecdh/x25519.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/crypto/ecdh/x25519.go136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/crypto/ecdh/x25519.go b/src/crypto/ecdh/x25519.go
new file mode 100644
index 0000000..dbc3ea9
--- /dev/null
+++ b/src/crypto/ecdh/x25519.go
@@ -0,0 +1,136 @@
+// Copyright 2022 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 ecdh
+
+import (
+ "crypto/internal/edwards25519/field"
+ "crypto/internal/randutil"
+ "errors"
+ "io"
+)
+
+var (
+ x25519PublicKeySize = 32
+ x25519PrivateKeySize = 32
+ x25519SharedSecretSize = 32
+)
+
+// X25519 returns a Curve which implements the X25519 function over Curve25519
+// (RFC 7748, Section 5).
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+func X25519() Curve { return x25519 }
+
+var x25519 = &x25519Curve{}
+
+type x25519Curve struct{}
+
+func (c *x25519Curve) String() string {
+ return "X25519"
+}
+
+func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ key := make([]byte, x25519PrivateKeySize)
+ randutil.MaybeReadByte(rand)
+ if _, err := io.ReadFull(rand, key); err != nil {
+ return nil, err
+ }
+ return c.NewPrivateKey(key)
+}
+
+func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
+ if len(key) != x25519PrivateKeySize {
+ return nil, errors.New("crypto/ecdh: invalid private key size")
+ }
+ return &PrivateKey{
+ curve: c,
+ privateKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *x25519Curve) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
+ if key.curve != c {
+ panic("crypto/ecdh: internal error: converting the wrong key type")
+ }
+ k := &PublicKey{
+ curve: key.curve,
+ publicKey: make([]byte, x25519PublicKeySize),
+ }
+ x25519Basepoint := [32]byte{9}
+ x25519ScalarMult(k.publicKey, key.privateKey, x25519Basepoint[:])
+ return k
+}
+
+func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
+ if len(key) != x25519PublicKeySize {
+ return nil, errors.New("crypto/ecdh: invalid public key")
+ }
+ return &PublicKey{
+ curve: c,
+ publicKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *x25519Curve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
+ out := make([]byte, x25519SharedSecretSize)
+ x25519ScalarMult(out, local.privateKey, remote.publicKey)
+ if isZero(out) {
+ return nil, errors.New("crypto/ecdh: bad X25519 remote ECDH input: low order point")
+ }
+ return out, nil
+}
+
+func x25519ScalarMult(dst, scalar, point []byte) {
+ var e [32]byte
+
+ copy(e[:], scalar[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
+ x1.SetBytes(point[:])
+ x2.One()
+ x3.Set(&x1)
+ z3.One()
+
+ swap := 0
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int(b)
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+ swap = int(b)
+
+ tmp0.Subtract(&x3, &z3)
+ tmp1.Subtract(&x2, &z2)
+ x2.Add(&x2, &z2)
+ z2.Add(&x3, &z3)
+ z3.Multiply(&tmp0, &x2)
+ z2.Multiply(&z2, &tmp1)
+ tmp0.Square(&tmp1)
+ tmp1.Square(&x2)
+ x3.Add(&z3, &z2)
+ z2.Subtract(&z3, &z2)
+ x2.Multiply(&tmp1, &tmp0)
+ tmp1.Subtract(&tmp1, &tmp0)
+ z2.Square(&z2)
+
+ z3.Mult32(&tmp1, 121666)
+ x3.Square(&x3)
+ tmp0.Add(&tmp0, &z3)
+ z3.Multiply(&x1, &z2)
+ z2.Multiply(&tmp1, &tmp0)
+ }
+
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+
+ z2.Invert(&z2)
+ x2.Multiply(&x2, &z2)
+ copy(dst[:], x2.Bytes())
+}