scheme.go raw

   1  package xwing
   2  
   3  import (
   4  	"bytes"
   5  	cryptoRand "crypto/rand"
   6  	"crypto/subtle"
   7  
   8  	"github.com/cloudflare/circl/kem"
   9  	"github.com/cloudflare/circl/kem/mlkem/mlkem768"
  10  )
  11  
  12  // This file contains the boilerplate code to connect X-Wing to the
  13  // generic KEM API.
  14  
  15  // Returns the generic KEM interface for  X-Wing PQ/T hybrid KEM.
  16  func Scheme() kem.Scheme { return scheme{} }
  17  
  18  type scheme struct{}
  19  
  20  func (scheme) Name() string               { return "X-Wing" }
  21  func (scheme) PublicKeySize() int         { return PublicKeySize }
  22  func (scheme) PrivateKeySize() int        { return PrivateKeySize }
  23  func (scheme) SeedSize() int              { return SeedSize }
  24  func (scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
  25  func (scheme) SharedKeySize() int         { return SharedKeySize }
  26  func (scheme) CiphertextSize() int        { return CiphertextSize }
  27  func (*PrivateKey) Scheme() kem.Scheme    { return scheme{} }
  28  func (*PublicKey) Scheme() kem.Scheme     { return scheme{} }
  29  
  30  func (sch scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
  31  	var seed [EncapsulationSeedSize]byte
  32  	_, err = cryptoRand.Read(seed[:])
  33  	if err != nil {
  34  		return
  35  	}
  36  	return sch.EncapsulateDeterministically(pk, seed[:])
  37  }
  38  
  39  func (scheme) EncapsulateDeterministically(
  40  	pk kem.PublicKey, seed []byte,
  41  ) ([]byte, []byte, error) {
  42  	if len(seed) != EncapsulationSeedSize {
  43  		return nil, nil, kem.ErrSeedSize
  44  	}
  45  	pub, ok := pk.(*PublicKey)
  46  	if !ok {
  47  		return nil, nil, kem.ErrTypeMismatch
  48  	}
  49  	var (
  50  		ct [CiphertextSize]byte
  51  		ss [SharedKeySize]byte
  52  	)
  53  	pub.EncapsulateTo(ct[:], ss[:], seed)
  54  	return ct[:], ss[:], nil
  55  }
  56  
  57  func (scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
  58  	var pk PublicKey
  59  	if len(buf) != PublicKeySize {
  60  		return nil, kem.ErrPubKeySize
  61  	}
  62  
  63  	if err := pk.Unpack(buf); err != nil {
  64  		return nil, err
  65  	}
  66  	return &pk, nil
  67  }
  68  
  69  func (scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
  70  	var sk PrivateKey
  71  	if len(buf) != PrivateKeySize {
  72  		return nil, kem.ErrPrivKeySize
  73  	}
  74  
  75  	sk.Unpack(buf)
  76  	return &sk, nil
  77  }
  78  
  79  func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
  80  	var ret [PrivateKeySize]byte
  81  	sk.Pack(ret[:])
  82  	return ret[:], nil
  83  }
  84  
  85  func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
  86  	oth, ok := other.(*PrivateKey)
  87  	if !ok {
  88  		return false
  89  	}
  90  	return sk.m.Equal(&oth.m) &&
  91  		subtle.ConstantTimeCompare(oth.x[:], sk.x[:]) == 1
  92  }
  93  
  94  func (sk *PrivateKey) Public() kem.PublicKey {
  95  	var pk PublicKey
  96  	pk.m = *(sk.m.Public().(*mlkem768.PublicKey))
  97  	pk.x = sk.xpk
  98  	return &pk
  99  }
 100  
 101  func (pk *PublicKey) Equal(other kem.PublicKey) bool {
 102  	oth, ok := other.(*PublicKey)
 103  	if !ok {
 104  		return false
 105  	}
 106  	return pk.m.Equal(&oth.m) && bytes.Equal(pk.x[:], oth.x[:])
 107  }
 108  
 109  func (pk *PublicKey) MarshalBinary() ([]byte, error) {
 110  	var ret [PublicKeySize]byte
 111  	pk.Pack(ret[:])
 112  	return ret[:], nil
 113  }
 114  
 115  func (scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
 116  	sk, pk := DeriveKeyPair(seed)
 117  	return pk, sk
 118  }
 119  
 120  func (scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
 121  	sk, pk, err := GenerateKeyPair(nil)
 122  	return pk, sk, err
 123  }
 124  
 125  func (scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
 126  	if len(ct) != CiphertextSize {
 127  		return nil, kem.ErrCiphertextSize
 128  	}
 129  
 130  	var ss [SharedKeySize]byte
 131  
 132  	priv, ok := sk.(*PrivateKey)
 133  	if !ok {
 134  		return nil, kem.ErrTypeMismatch
 135  	}
 136  
 137  	priv.DecapsulateTo(ss[:], ct[:])
 138  
 139  	return ss[:], nil
 140  }
 141