github.com/cloudflare/circl@v1.5.0/kem/hybrid/hybrid.go (about)

     1  // Package hybrid defines several hybrid classical/quantum KEMs for use in TLS.
     2  //
     3  // Hybrid KEMs in TLS are created by simple concatenation
     4  // of shared secrets, cipher texts, public keys, etc.
     5  // This is safe for TLS, see eg.
     6  //
     7  //	https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/
     8  //	https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf
     9  //
    10  // Note that this approach is not proven secure in broader context.
    11  //
    12  // For deriving a KEM keypair deterministically and encapsulating
    13  // deterministically, we expand a single seed to both using SHAKE256,
    14  // so that a non-uniform seed (such as a shared secret generated by a hybrid
    15  // KEM where one of the KEMs is weak) doesn't impact just one of the KEMs.
    16  //
    17  // Of our XOF (SHAKE256), we desire two security properties:
    18  //
    19  //  1. The internal state of the XOF should be big enough so that we
    20  //     do not loose entropy.
    21  //  2. From one of the new seeds, we shouldn't be able to derive
    22  //     the other or the original seed.
    23  //
    24  // SHAKE256, and all siblings in the SHA3 family, have a 200B internal
    25  // state, so (1) is fine if our seeds are less than 200B.
    26  // If SHAKE256 is computationally indistinguishable from a random
    27  // sponge, then it affords us 256b security against (2) by the
    28  // flat sponge claim [https://keccak.team/files/SpongeFunctions.pdf].
    29  // None of the implemented schemes claim more than 256b security
    30  // and so SHAKE256 will do fine.
    31  package hybrid
    32  
    33  import (
    34  	"errors"
    35  
    36  	"github.com/cloudflare/circl/internal/sha3"
    37  	"github.com/cloudflare/circl/kem"
    38  	"github.com/cloudflare/circl/kem/kyber/kyber1024"
    39  	"github.com/cloudflare/circl/kem/kyber/kyber512"
    40  	"github.com/cloudflare/circl/kem/kyber/kyber768"
    41  	"github.com/cloudflare/circl/kem/mlkem/mlkem768"
    42  )
    43  
    44  var ErrUninitialized = errors.New("public or private key not initialized")
    45  
    46  // Returns the hybrid KEM of Kyber512Draft00 and X25519.
    47  func Kyber512X25519() kem.Scheme { return kyber512X }
    48  
    49  // Returns the hybrid KEM of Kyber768Draft00 and X25519.
    50  func Kyber768X25519() kem.Scheme { return kyber768X }
    51  
    52  // Returns the hybrid KEM of Kyber768Draft00 and X448.
    53  func Kyber768X448() kem.Scheme { return kyber768X4 }
    54  
    55  // Returns the hybrid KEM of Kyber1024Draft00 and X448.
    56  func Kyber1024X448() kem.Scheme { return kyber1024X }
    57  
    58  // Returns the hybrid KEM of Kyber768Draft00 and P-256.
    59  func P256Kyber768Draft00() kem.Scheme { return p256Kyber768Draft00 }
    60  
    61  // Returns the hybrid KEM of ML-KEM-768 and X25519.
    62  // https://www.ietf.org/archive/id/draft-kwiatkowski-tls-ecdhe-mlkem-01.html
    63  func X25519MLKEM768() kem.Scheme { return xmlkem768 }
    64  
    65  var p256Kyber768Draft00 kem.Scheme = &scheme{
    66  	"P256Kyber768Draft00",
    67  	p256Kem,
    68  	kyber768.Scheme(),
    69  }
    70  
    71  var kyber512X kem.Scheme = &scheme{
    72  	"Kyber512-X25519",
    73  	x25519Kem,
    74  	kyber512.Scheme(),
    75  }
    76  
    77  var kyber768X kem.Scheme = &scheme{
    78  	"Kyber768-X25519",
    79  	x25519Kem,
    80  	kyber768.Scheme(),
    81  }
    82  
    83  var kyber768X4 kem.Scheme = &scheme{
    84  	"Kyber768-X448",
    85  	x448Kem,
    86  	kyber768.Scheme(),
    87  }
    88  
    89  var kyber1024X kem.Scheme = &scheme{
    90  	"Kyber1024-X448",
    91  	x448Kem,
    92  	kyber1024.Scheme(),
    93  }
    94  
    95  var xmlkem768 kem.Scheme = &scheme{
    96  	"X25519MLKEM768",
    97  	mlkem768.Scheme(),
    98  	x25519Kem,
    99  }
   100  
   101  // Public key of a hybrid KEM.
   102  type publicKey struct {
   103  	scheme *scheme
   104  	first  kem.PublicKey
   105  	second kem.PublicKey
   106  }
   107  
   108  // Private key of a hybrid KEM.
   109  type privateKey struct {
   110  	scheme *scheme
   111  	first  kem.PrivateKey
   112  	second kem.PrivateKey
   113  }
   114  
   115  // Scheme for a hybrid KEM.
   116  type scheme struct {
   117  	name   string
   118  	first  kem.Scheme
   119  	second kem.Scheme
   120  }
   121  
   122  func (sch *scheme) Name() string { return sch.name }
   123  func (sch *scheme) PublicKeySize() int {
   124  	return sch.first.PublicKeySize() + sch.second.PublicKeySize()
   125  }
   126  
   127  func (sch *scheme) PrivateKeySize() int {
   128  	return sch.first.PrivateKeySize() + sch.second.PrivateKeySize()
   129  }
   130  
   131  func (sch *scheme) SeedSize() int {
   132  	first := sch.first.SeedSize()
   133  	second := sch.second.SeedSize()
   134  	ret := second
   135  	if first > second {
   136  		ret = first
   137  	}
   138  	return ret
   139  }
   140  
   141  func (sch *scheme) SharedKeySize() int {
   142  	return sch.first.SharedKeySize() + sch.second.SharedKeySize()
   143  }
   144  
   145  func (sch *scheme) CiphertextSize() int {
   146  	return sch.first.CiphertextSize() + sch.second.CiphertextSize()
   147  }
   148  
   149  func (sch *scheme) EncapsulationSeedSize() int {
   150  	first := sch.first.EncapsulationSeedSize()
   151  	second := sch.second.EncapsulationSeedSize()
   152  	ret := second
   153  	if first > second {
   154  		ret = first
   155  	}
   156  	return ret
   157  }
   158  
   159  func (sk *privateKey) Scheme() kem.Scheme { return sk.scheme }
   160  func (pk *publicKey) Scheme() kem.Scheme  { return pk.scheme }
   161  
   162  func (sk *privateKey) MarshalBinary() ([]byte, error) {
   163  	if sk.first == nil || sk.second == nil {
   164  		return nil, ErrUninitialized
   165  	}
   166  	first, err := sk.first.MarshalBinary()
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	second, err := sk.second.MarshalBinary()
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	return append(first, second...), nil
   175  }
   176  
   177  func (sk *privateKey) Equal(other kem.PrivateKey) bool {
   178  	oth, ok := other.(*privateKey)
   179  	if !ok {
   180  		return false
   181  	}
   182  	if sk.first == nil && sk.second == nil && oth.first == nil && oth.second == nil {
   183  		return true
   184  	}
   185  	if sk.first == nil || sk.second == nil || oth.first == nil || oth.second == nil {
   186  		return false
   187  	}
   188  	return sk.first.Equal(oth.first) && sk.second.Equal(oth.second)
   189  }
   190  
   191  func (sk *privateKey) Public() kem.PublicKey {
   192  	return &publicKey{sk.scheme, sk.first.Public(), sk.second.Public()}
   193  }
   194  
   195  func (pk *publicKey) Equal(other kem.PublicKey) bool {
   196  	oth, ok := other.(*publicKey)
   197  	if !ok {
   198  		return false
   199  	}
   200  	if pk.first == nil && pk.second == nil && oth.first == nil && oth.second == nil {
   201  		return true
   202  	}
   203  	if pk.first == nil || pk.second == nil || oth.first == nil || oth.second == nil {
   204  		return false
   205  	}
   206  	return pk.first.Equal(oth.first) && pk.second.Equal(oth.second)
   207  }
   208  
   209  func (pk *publicKey) MarshalBinary() ([]byte, error) {
   210  	if pk.first == nil || pk.second == nil {
   211  		return nil, ErrUninitialized
   212  	}
   213  	first, err := pk.first.MarshalBinary()
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	second, err := pk.second.MarshalBinary()
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  	return append(first, second...), nil
   222  }
   223  
   224  func (sch *scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
   225  	pk1, sk1, err := sch.first.GenerateKeyPair()
   226  	if err != nil {
   227  		return nil, nil, err
   228  	}
   229  	pk2, sk2, err := sch.second.GenerateKeyPair()
   230  	if err != nil {
   231  		return nil, nil, err
   232  	}
   233  
   234  	return &publicKey{sch, pk1, pk2}, &privateKey{sch, sk1, sk2}, nil
   235  }
   236  
   237  func (sch *scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
   238  	if len(seed) != sch.SeedSize() {
   239  		panic(kem.ErrSeedSize)
   240  	}
   241  	h := sha3.NewShake256()
   242  	_, _ = h.Write(seed)
   243  	first := make([]byte, sch.first.SeedSize())
   244  	second := make([]byte, sch.second.SeedSize())
   245  	_, _ = h.Read(first)
   246  	_, _ = h.Read(second)
   247  
   248  	pk1, sk1 := sch.first.DeriveKeyPair(first)
   249  	pk2, sk2 := sch.second.DeriveKeyPair(second)
   250  
   251  	return &publicKey{sch, pk1, pk2}, &privateKey{sch, sk1, sk2}
   252  }
   253  
   254  func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
   255  	pub, ok := pk.(*publicKey)
   256  	if !ok {
   257  		return nil, nil, kem.ErrTypeMismatch
   258  	}
   259  
   260  	ct1, ss1, err := sch.first.Encapsulate(pub.first)
   261  	if err != nil {
   262  		return nil, nil, err
   263  	}
   264  
   265  	ct2, ss2, err := sch.second.Encapsulate(pub.second)
   266  	if err != nil {
   267  		return nil, nil, err
   268  	}
   269  
   270  	return append(ct1, ct2...), append(ss1, ss2...), nil
   271  }
   272  
   273  func (sch *scheme) EncapsulateDeterministically(
   274  	pk kem.PublicKey, seed []byte,
   275  ) (ct, ss []byte, err error) {
   276  	if len(seed) != sch.EncapsulationSeedSize() {
   277  		return nil, nil, kem.ErrSeedSize
   278  	}
   279  
   280  	h := sha3.NewShake256()
   281  	_, _ = h.Write(seed)
   282  	first := make([]byte, sch.first.EncapsulationSeedSize())
   283  	second := make([]byte, sch.second.EncapsulationSeedSize())
   284  	_, _ = h.Read(first)
   285  	_, _ = h.Read(second)
   286  
   287  	pub, ok := pk.(*publicKey)
   288  	if !ok {
   289  		return nil, nil, kem.ErrTypeMismatch
   290  	}
   291  
   292  	ct1, ss1, err := sch.first.EncapsulateDeterministically(pub.first, first)
   293  	if err != nil {
   294  		return nil, nil, err
   295  	}
   296  	ct2, ss2, err := sch.second.EncapsulateDeterministically(pub.second, second)
   297  	if err != nil {
   298  		return nil, nil, err
   299  	}
   300  	return append(ct1, ct2...), append(ss1, ss2...), nil
   301  }
   302  
   303  func (sch *scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
   304  	if len(ct) != sch.CiphertextSize() {
   305  		return nil, kem.ErrCiphertextSize
   306  	}
   307  
   308  	priv, ok := sk.(*privateKey)
   309  	if !ok {
   310  		return nil, kem.ErrTypeMismatch
   311  	}
   312  
   313  	firstSize := sch.first.CiphertextSize()
   314  	ss1, err := sch.first.Decapsulate(priv.first, ct[:firstSize])
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  	ss2, err := sch.second.Decapsulate(priv.second, ct[firstSize:])
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	return append(ss1, ss2...), nil
   323  }
   324  
   325  func (sch *scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
   326  	if len(buf) != sch.PublicKeySize() {
   327  		return nil, kem.ErrPubKeySize
   328  	}
   329  	firstSize := sch.first.PublicKeySize()
   330  	pk1, err := sch.first.UnmarshalBinaryPublicKey(buf[:firstSize])
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	pk2, err := sch.second.UnmarshalBinaryPublicKey(buf[firstSize:])
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  	return &publicKey{sch, pk1, pk2}, nil
   339  }
   340  
   341  func (sch *scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
   342  	if len(buf) != sch.PrivateKeySize() {
   343  		return nil, kem.ErrPrivKeySize
   344  	}
   345  	firstSize := sch.first.PrivateKeySize()
   346  	sk1, err := sch.first.UnmarshalBinaryPrivateKey(buf[:firstSize])
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  	sk2, err := sch.second.UnmarshalBinaryPrivateKey(buf[firstSize:])
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  	return &privateKey{sch, sk1, sk2}, nil
   355  }