Source file src/crypto/ecdh/x25519.go

     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  
     5  package ecdh
     6  
     7  import (
     8  	"crypto/internal/edwards25519/field"
     9  	"crypto/internal/randutil"
    10  	"errors"
    11  	"io"
    12  )
    13  
    14  var (
    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.
    25  func X25519() Curve { return x25519 }
    26  
    27  var x25519 = &x25519Curve{}
    28  
    29  type x25519Curve struct{}
    30  
    31  func (c *x25519Curve) String() string {
    32  	return "X25519"
    33  }
    34  
    35  func (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  
    44  func (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  
    54  func (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  
    67  func (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  
    77  func (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  
    86  func 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  

View as plain text