github.com/cloudflare/circl@v1.5.0/hpke/shortkem.go (about)

     1  package hpke
     2  
     3  import (
     4  	"crypto/elliptic"
     5  	"crypto/rand"
     6  	"crypto/subtle"
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/cloudflare/circl/kem"
    11  )
    12  
    13  type shortKEM struct {
    14  	dhKemBase
    15  	elliptic.Curve
    16  }
    17  
    18  func (s shortKEM) PrivateKeySize() int        { return s.byteSize() }
    19  func (s shortKEM) SeedSize() int              { return s.byteSize() }
    20  func (s shortKEM) CiphertextSize() int        { return 1 + 2*s.byteSize() }
    21  func (s shortKEM) PublicKeySize() int         { return 1 + 2*s.byteSize() }
    22  func (s shortKEM) EncapsulationSeedSize() int { return s.byteSize() }
    23  
    24  func (s shortKEM) byteSize() int { return (s.Params().BitSize + 7) / 8 }
    25  
    26  func (s shortKEM) sizeDH() int { return s.byteSize() }
    27  func (s shortKEM) calcDH(dh []byte, sk kem.PrivateKey, pk kem.PublicKey) error {
    28  	PK := pk.(*shortKEMPubKey)
    29  	SK := sk.(*shortKEMPrivKey)
    30  	l := len(dh)
    31  	x, _ := s.ScalarMult(PK.x, PK.y, SK.priv) // only x-coordinate is used.
    32  	if x.Sign() == 0 {
    33  		return ErrInvalidKEMSharedSecret
    34  	}
    35  	b := x.Bytes()
    36  	copy(dh[l-len(b):l], b)
    37  	return nil
    38  }
    39  
    40  // Deterministically derives a keypair from a seed. If you're unsure,
    41  // you're better off using GenerateKey().
    42  //
    43  // Panics if seed is not of length SeedSize().
    44  func (s shortKEM) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
    45  	// Implementation based on
    46  	// https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-07.html#name-derivekeypair
    47  	if len(seed) != s.SeedSize() {
    48  		panic(kem.ErrSeedSize)
    49  	}
    50  
    51  	bitmask := byte(0xFF)
    52  	if s.Params().BitSize == 521 {
    53  		bitmask = 0x01
    54  	}
    55  
    56  	dkpPrk := s.labeledExtract([]byte(""), []byte("dkp_prk"), seed)
    57  	var bytes []byte
    58  	ctr := 0
    59  	for skBig := new(big.Int); skBig.Sign() == 0 || skBig.Cmp(s.Params().N) >= 0; ctr++ {
    60  		if ctr > 255 {
    61  			panic("derive key error")
    62  		}
    63  		bytes = s.labeledExpand(
    64  			dkpPrk,
    65  			[]byte("candidate"),
    66  			[]byte{byte(ctr)},
    67  			uint16(s.byteSize()),
    68  		)
    69  		bytes[0] &= bitmask
    70  		skBig.SetBytes(bytes)
    71  	}
    72  	l := s.PrivateKeySize()
    73  	sk := &shortKEMPrivKey{s, make([]byte, l), nil}
    74  	copy(sk.priv[l-len(bytes):], bytes)
    75  	return sk.Public(), sk
    76  }
    77  
    78  func (s shortKEM) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
    79  	sk, x, y, err := elliptic.GenerateKey(s, rand.Reader)
    80  	pub := &shortKEMPubKey{s, x, y}
    81  	return pub, &shortKEMPrivKey{s, sk, pub}, err
    82  }
    83  
    84  func (s shortKEM) UnmarshalBinaryPrivateKey(data []byte) (kem.PrivateKey, error) {
    85  	l := s.PrivateKeySize()
    86  	if len(data) < l {
    87  		return nil, ErrInvalidKEMPrivateKey
    88  	}
    89  	sk := &shortKEMPrivKey{s, make([]byte, l), nil}
    90  	copy(sk.priv[l-len(data):l], data[:l])
    91  	if !sk.validate() {
    92  		return nil, ErrInvalidKEMPrivateKey
    93  	}
    94  
    95  	return sk, nil
    96  }
    97  
    98  func (s shortKEM) UnmarshalBinaryPublicKey(data []byte) (kem.PublicKey, error) {
    99  	x, y := elliptic.Unmarshal(s, data)
   100  	if x == nil {
   101  		return nil, ErrInvalidKEMPublicKey
   102  	}
   103  	key := &shortKEMPubKey{s, x, y}
   104  	if !key.validate() {
   105  		return nil, ErrInvalidKEMPublicKey
   106  	}
   107  	return key, nil
   108  }
   109  
   110  type shortKEMPubKey struct {
   111  	scheme shortKEM
   112  	x, y   *big.Int
   113  }
   114  
   115  func (k *shortKEMPubKey) String() string {
   116  	return fmt.Sprintf("x: %v\ny: %v", k.x.Text(16), k.y.Text(16))
   117  }
   118  func (k *shortKEMPubKey) Scheme() kem.Scheme { return k.scheme }
   119  func (k *shortKEMPubKey) MarshalBinary() ([]byte, error) {
   120  	return elliptic.Marshal(k.scheme, k.x, k.y), nil
   121  }
   122  
   123  func (k *shortKEMPubKey) Equal(pk kem.PublicKey) bool {
   124  	k1, ok := pk.(*shortKEMPubKey)
   125  	return ok &&
   126  		k.scheme.Params().Name == k1.scheme.Params().Name &&
   127  		k.x.Cmp(k1.x) == 0 &&
   128  		k.y.Cmp(k1.y) == 0
   129  }
   130  
   131  func (k *shortKEMPubKey) validate() bool {
   132  	p := k.scheme.Params().P
   133  	notAtInfinity := k.x.Sign() > 0 && k.y.Sign() > 0
   134  	lessThanP := k.x.Cmp(p) < 0 && k.y.Cmp(p) < 0
   135  	onCurve := k.scheme.IsOnCurve(k.x, k.y)
   136  	return notAtInfinity && lessThanP && onCurve
   137  }
   138  
   139  type shortKEMPrivKey struct {
   140  	scheme shortKEM
   141  	priv   []byte
   142  	pub    *shortKEMPubKey
   143  }
   144  
   145  func (k *shortKEMPrivKey) String() string     { return fmt.Sprintf("%x", k.priv) }
   146  func (k *shortKEMPrivKey) Scheme() kem.Scheme { return k.scheme }
   147  func (k *shortKEMPrivKey) MarshalBinary() ([]byte, error) {
   148  	return append(make([]byte, 0, k.scheme.PrivateKeySize()), k.priv...), nil
   149  }
   150  
   151  func (k *shortKEMPrivKey) Equal(pk kem.PrivateKey) bool {
   152  	k1, ok := pk.(*shortKEMPrivKey)
   153  	return ok &&
   154  		k.scheme.Params().Name == k1.scheme.Params().Name &&
   155  		subtle.ConstantTimeCompare(k.priv, k1.priv) == 1
   156  }
   157  
   158  func (k *shortKEMPrivKey) Public() kem.PublicKey {
   159  	if k.pub == nil {
   160  		x, y := k.scheme.ScalarBaseMult(k.priv)
   161  		k.pub = &shortKEMPubKey{k.scheme, x, y}
   162  	}
   163  	return k.pub
   164  }
   165  
   166  func (k *shortKEMPrivKey) validate() bool {
   167  	n := new(big.Int).SetBytes(k.priv)
   168  	order := k.scheme.Curve.Params().N
   169  	return len(k.priv) == k.scheme.PrivateKeySize() && n.Cmp(order) < 0
   170  }