mirror of https://github.com/golang/go.git
137 lines
3.1 KiB
Go
137 lines
3.1 KiB
Go
// 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())
|
|
}
|