1// Copyright 2022 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ecdh
6
7import (
8	"crypto/internal/edwards25519/field"
9	"crypto/internal/randutil"
10	"errors"
11	"io"
12)
13
14var (
15	x25519PublicKeySize    = 32
16	x25519PrivateKeySize   = 32
17	x25519SharedSecretSize = 32
18)
19
20// X25519 returns a [Curve] which implements the X25519 function over Curve25519
21// (RFC 7748, Section 5).
22//
23// Multiple invocations of this function will return the same value, so it can
24// be used for equality checks and switch statements.
25func X25519() Curve { return x25519 }
26
27var x25519 = &x25519Curve{}
28
29type x25519Curve struct{}
30
31func (c *x25519Curve) String() string {
32	return "X25519"
33}
34
35func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
36	key := make([]byte, x25519PrivateKeySize)
37	randutil.MaybeReadByte(rand)
38	if _, err := io.ReadFull(rand, key); err != nil {
39		return nil, err
40	}
41	return c.NewPrivateKey(key)
42}
43
44func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
45	if len(key) != x25519PrivateKeySize {
46		return nil, errors.New("crypto/ecdh: invalid private key size")
47	}
48	return &PrivateKey{
49		curve:      c,
50		privateKey: append([]byte{}, key...),
51	}, nil
52}
53
54func (c *x25519Curve) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
55	if key.curve != c {
56		panic("crypto/ecdh: internal error: converting the wrong key type")
57	}
58	k := &PublicKey{
59		curve:     key.curve,
60		publicKey: make([]byte, x25519PublicKeySize),
61	}
62	x25519Basepoint := [32]byte{9}
63	x25519ScalarMult(k.publicKey, key.privateKey, x25519Basepoint[:])
64	return k
65}
66
67func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
68	if len(key) != x25519PublicKeySize {
69		return nil, errors.New("crypto/ecdh: invalid public key")
70	}
71	return &PublicKey{
72		curve:     c,
73		publicKey: append([]byte{}, key...),
74	}, nil
75}
76
77func (c *x25519Curve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
78	out := make([]byte, x25519SharedSecretSize)
79	x25519ScalarMult(out, local.privateKey, remote.publicKey)
80	if isZero(out) {
81		return nil, errors.New("crypto/ecdh: bad X25519 remote ECDH input: low order point")
82	}
83	return out, nil
84}
85
86func x25519ScalarMult(dst, scalar, point []byte) {
87	var e [32]byte
88
89	copy(e[:], scalar[:])
90	e[0] &= 248
91	e[31] &= 127
92	e[31] |= 64
93
94	var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
95	x1.SetBytes(point[:])
96	x2.One()
97	x3.Set(&x1)
98	z3.One()
99
100	swap := 0
101	for pos := 254; pos >= 0; pos-- {
102		b := e[pos/8] >> uint(pos&7)
103		b &= 1
104		swap ^= int(b)
105		x2.Swap(&x3, swap)
106		z2.Swap(&z3, swap)
107		swap = int(b)
108
109		tmp0.Subtract(&x3, &z3)
110		tmp1.Subtract(&x2, &z2)
111		x2.Add(&x2, &z2)
112		z2.Add(&x3, &z3)
113		z3.Multiply(&tmp0, &x2)
114		z2.Multiply(&z2, &tmp1)
115		tmp0.Square(&tmp1)
116		tmp1.Square(&x2)
117		x3.Add(&z3, &z2)
118		z2.Subtract(&z3, &z2)
119		x2.Multiply(&tmp1, &tmp0)
120		tmp1.Subtract(&tmp1, &tmp0)
121		z2.Square(&z2)
122
123		z3.Mult32(&tmp1, 121666)
124		x3.Square(&x3)
125		tmp0.Add(&tmp0, &z3)
126		z3.Multiply(&x1, &z2)
127		z2.Multiply(&tmp1, &tmp0)
128	}
129
130	x2.Swap(&x3, swap)
131	z2.Swap(&z3, swap)
132
133	z2.Invert(&z2)
134	x2.Multiply(&x2, &z2)
135	copy(dst[:], x2.Bytes())
136}
137