github.com/lestrrat-go/jwx/v2@v2.0.21/x25519/x25519.go (about)

     1  package x25519
     2  
     3  import (
     4  	"bytes"
     5  	"crypto"
     6  	cryptorand "crypto/rand"
     7  	"fmt"
     8  	"io"
     9  
    10  	"golang.org/x/crypto/curve25519"
    11  )
    12  
    13  // This mirrors ed25519's structure for private/public "keys". jwx
    14  // requires dedicated types for these as they drive
    15  // serialization/deserialization logic, as well as encryption types.
    16  //
    17  // Note that with the x25519 scheme, the private key is a sequence of
    18  // 32 bytes, while the public key is the result of X25519(private,
    19  // basepoint).
    20  //
    21  // Portions of this file are from Go's ed25519.go, which is
    22  // Copyright 2016 The Go Authors. All rights reserved.
    23  
    24  const (
    25  	// PublicKeySize is the size, in bytes, of public keys as used in this package.
    26  	PublicKeySize = 32
    27  	// PrivateKeySize is the size, in bytes, of private keys as used in this package.
    28  	PrivateKeySize = 64
    29  	// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
    30  	SeedSize = 32
    31  )
    32  
    33  // PublicKey is the type of X25519 public keys
    34  type PublicKey []byte
    35  
    36  // Any methods implemented on PublicKey might need to also be implemented on
    37  // PrivateKey, as the latter embeds the former and will expose its methods.
    38  
    39  // Equal reports whether pub and x have the same value.
    40  func (pub PublicKey) Equal(x crypto.PublicKey) bool {
    41  	xx, ok := x.(PublicKey)
    42  	if !ok {
    43  		return false
    44  	}
    45  	return bytes.Equal(pub, xx)
    46  }
    47  
    48  // PrivateKey is the type of X25519 private key
    49  type PrivateKey []byte
    50  
    51  // Public returns the PublicKey corresponding to priv.
    52  func (priv PrivateKey) Public() crypto.PublicKey {
    53  	publicKey := make([]byte, PublicKeySize)
    54  	copy(publicKey, priv[SeedSize:])
    55  	return PublicKey(publicKey)
    56  }
    57  
    58  // Equal reports whether priv and x have the same value.
    59  func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
    60  	xx, ok := x.(PrivateKey)
    61  	if !ok {
    62  		return false
    63  	}
    64  	return bytes.Equal(priv, xx)
    65  }
    66  
    67  // Seed returns the private key seed corresponding to priv. It is provided for
    68  // interoperability with RFC 7748. RFC 7748's private keys correspond to seeds
    69  // in this package.
    70  func (priv PrivateKey) Seed() []byte {
    71  	seed := make([]byte, SeedSize)
    72  	copy(seed, priv[:SeedSize])
    73  	return seed
    74  }
    75  
    76  // NewKeyFromSeed calculates a private key from a seed. It will return
    77  // an error if len(seed) is not SeedSize. This function is provided
    78  // for interoperability with RFC 7748. RFC 7748's private keys
    79  // correspond to seeds in this package.
    80  func NewKeyFromSeed(seed []byte) (PrivateKey, error) {
    81  	privateKey := make([]byte, PrivateKeySize)
    82  	if len(seed) != SeedSize {
    83  		return nil, fmt.Errorf("unexpected seed size: %d", len(seed))
    84  	}
    85  	copy(privateKey, seed)
    86  	public, err := curve25519.X25519(seed, curve25519.Basepoint)
    87  	if err != nil {
    88  		return nil, fmt.Errorf(`failed to compute public key: %w`, err)
    89  	}
    90  	copy(privateKey[SeedSize:], public)
    91  
    92  	return privateKey, nil
    93  }
    94  
    95  // GenerateKey generates a public/private key pair using entropy from rand.
    96  // If rand is nil, crypto/rand.Reader will be used.
    97  func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
    98  	if rand == nil {
    99  		rand = cryptorand.Reader
   100  	}
   101  
   102  	seed := make([]byte, SeedSize)
   103  	if _, err := io.ReadFull(rand, seed); err != nil {
   104  		return nil, nil, err
   105  	}
   106  
   107  	privateKey, err := NewKeyFromSeed(seed)
   108  	if err != nil {
   109  		return nil, nil, err
   110  	}
   111  	publicKey := make([]byte, PublicKeySize)
   112  	copy(publicKey, privateKey[SeedSize:])
   113  
   114  	return publicKey, privateKey, nil
   115  }