...

Source file src/github.com/cloudflare/circl/kem/hybrid/hybrid.go

Documentation: github.com/cloudflare/circl/kem/hybrid

     1  // Package hybrid defines several hybrid classical/quantum KEMs.
     2  //
     3  // KEMs are combined by simple concatenation of shared secrets, cipher texts,
     4  // public keys, etc, see
     5  //
     6  //	https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/
     7  //	https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf
     8  //
     9  // Note that this is only fine if the shared secret is used in its entirety
    10  // in a next step, such as being hashed or used as key.
    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  )
    42  
    43  var ErrUninitialized = errors.New("public or private key not initialized")
    44  
    45  // Returns the hybrid KEM of Kyber512Draft00 and X25519.
    46  func Kyber512X25519() kem.Scheme { return kyber512X }
    47  
    48  // Returns the hybrid KEM of Kyber768Draft00 and X25519.
    49  func Kyber768X25519() kem.Scheme { return kyber768X }
    50  
    51  // Returns the hybrid KEM of Kyber768Draft00 and X448.
    52  func Kyber768X448() kem.Scheme { return kyber768X4 }
    53  
    54  // Returns the hybrid KEM of Kyber1024Draft00 and X448.
    55  func Kyber1024X448() kem.Scheme { return kyber1024X }
    56  
    57  // Returns the hybrid KEM of Kyber768Draft00 and P-256.
    58  func P256Kyber768Draft00() kem.Scheme { return p256Kyber768Draft00 }
    59  
    60  var p256Kyber768Draft00 kem.Scheme = &scheme{
    61  	"P256Kyber768Draft00",
    62  	p256Kem,
    63  	kyber768.Scheme(),
    64  }
    65  
    66  var kyber512X kem.Scheme = &scheme{
    67  	"Kyber512-X25519",
    68  	x25519Kem,
    69  	kyber512.Scheme(),
    70  }
    71  
    72  var kyber768X kem.Scheme = &scheme{
    73  	"Kyber768-X25519",
    74  	x25519Kem,
    75  	kyber768.Scheme(),
    76  }
    77  
    78  var kyber768X4 kem.Scheme = &scheme{
    79  	"Kyber768-X448",
    80  	x448Kem,
    81  	kyber768.Scheme(),
    82  }
    83  
    84  var kyber1024X kem.Scheme = &scheme{
    85  	"Kyber1024-X448",
    86  	x448Kem,
    87  	kyber1024.Scheme(),
    88  }
    89  
    90  // Public key of a hybrid KEM.
    91  type publicKey struct {
    92  	scheme *scheme
    93  	first  kem.PublicKey
    94  	second kem.PublicKey
    95  }
    96  
    97  // Private key of a hybrid KEM.
    98  type privateKey struct {
    99  	scheme *scheme
   100  	first  kem.PrivateKey
   101  	second kem.PrivateKey
   102  }
   103  
   104  // Scheme for a hybrid KEM.
   105  type scheme struct {
   106  	name   string
   107  	first  kem.Scheme
   108  	second kem.Scheme
   109  }
   110  
   111  func (sch *scheme) Name() string { return sch.name }
   112  func (sch *scheme) PublicKeySize() int {
   113  	return sch.first.PublicKeySize() + sch.second.PublicKeySize()
   114  }
   115  
   116  func (sch *scheme) PrivateKeySize() int {
   117  	return sch.first.PrivateKeySize() + sch.second.PrivateKeySize()
   118  }
   119  
   120  func (sch *scheme) SeedSize() int {
   121  	first := sch.first.SeedSize()
   122  	second := sch.second.SeedSize()
   123  	ret := second
   124  	if first > second {
   125  		ret = first
   126  	}
   127  	return ret
   128  }
   129  
   130  func (sch *scheme) SharedKeySize() int {
   131  	return sch.first.SharedKeySize() + sch.second.SharedKeySize()
   132  }
   133  
   134  func (sch *scheme) CiphertextSize() int {
   135  	return sch.first.CiphertextSize() + sch.second.CiphertextSize()
   136  }
   137  
   138  func (sch *scheme) EncapsulationSeedSize() int {
   139  	first := sch.first.EncapsulationSeedSize()
   140  	second := sch.second.EncapsulationSeedSize()
   141  	ret := second
   142  	if first > second {
   143  		ret = first
   144  	}
   145  	return ret
   146  }
   147  
   148  func (sk *privateKey) Scheme() kem.Scheme { return sk.scheme }
   149  func (pk *publicKey) Scheme() kem.Scheme  { return pk.scheme }
   150  
   151  func (sk *privateKey) MarshalBinary() ([]byte, error) {
   152  	if sk.first == nil || sk.second == nil {
   153  		return nil, ErrUninitialized
   154  	}
   155  	first, err := sk.first.MarshalBinary()
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	second, err := sk.second.MarshalBinary()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	return append(first, second...), nil
   164  }
   165  
   166  func (sk *privateKey) Equal(other kem.PrivateKey) bool {
   167  	oth, ok := other.(*privateKey)
   168  	if !ok {
   169  		return false
   170  	}
   171  	if sk.first == nil && sk.second == nil && oth.first == nil && oth.second == nil {
   172  		return true
   173  	}
   174  	if sk.first == nil || sk.second == nil || oth.first == nil || oth.second == nil {
   175  		return false
   176  	}
   177  	return sk.first.Equal(oth.first) && sk.second.Equal(oth.second)
   178  }
   179  
   180  func (sk *privateKey) Public() kem.PublicKey {
   181  	return &publicKey{sk.scheme, sk.first.Public(), sk.second.Public()}
   182  }
   183  
   184  func (pk *publicKey) Equal(other kem.PublicKey) bool {
   185  	oth, ok := other.(*publicKey)
   186  	if !ok {
   187  		return false
   188  	}
   189  	if pk.first == nil && pk.second == nil && oth.first == nil && oth.second == nil {
   190  		return true
   191  	}
   192  	if pk.first == nil || pk.second == nil || oth.first == nil || oth.second == nil {
   193  		return false
   194  	}
   195  	return pk.first.Equal(oth.first) && pk.second.Equal(oth.second)
   196  }
   197  
   198  func (pk *publicKey) MarshalBinary() ([]byte, error) {
   199  	if pk.first == nil || pk.second == nil {
   200  		return nil, ErrUninitialized
   201  	}
   202  	first, err := pk.first.MarshalBinary()
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	second, err := pk.second.MarshalBinary()
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  	return append(first, second...), nil
   211  }
   212  
   213  func (sch *scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
   214  	pk1, sk1, err := sch.first.GenerateKeyPair()
   215  	if err != nil {
   216  		return nil, nil, err
   217  	}
   218  	pk2, sk2, err := sch.second.GenerateKeyPair()
   219  	if err != nil {
   220  		return nil, nil, err
   221  	}
   222  
   223  	return &publicKey{sch, pk1, pk2}, &privateKey{sch, sk1, sk2}, nil
   224  }
   225  
   226  func (sch *scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
   227  	if len(seed) != sch.SeedSize() {
   228  		panic(kem.ErrSeedSize)
   229  	}
   230  	h := sha3.NewShake256()
   231  	_, _ = h.Write(seed)
   232  	first := make([]byte, sch.first.SeedSize())
   233  	second := make([]byte, sch.second.SeedSize())
   234  	_, _ = h.Read(first)
   235  	_, _ = h.Read(second)
   236  
   237  	pk1, sk1 := sch.first.DeriveKeyPair(first)
   238  	pk2, sk2 := sch.second.DeriveKeyPair(second)
   239  
   240  	return &publicKey{sch, pk1, pk2}, &privateKey{sch, sk1, sk2}
   241  }
   242  
   243  func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
   244  	pub, ok := pk.(*publicKey)
   245  	if !ok {
   246  		return nil, nil, kem.ErrTypeMismatch
   247  	}
   248  
   249  	ct1, ss1, err := sch.first.Encapsulate(pub.first)
   250  	if err != nil {
   251  		return nil, nil, err
   252  	}
   253  
   254  	ct2, ss2, err := sch.second.Encapsulate(pub.second)
   255  	if err != nil {
   256  		return nil, nil, err
   257  	}
   258  
   259  	return append(ct1, ct2...), append(ss1, ss2...), nil
   260  }
   261  
   262  func (sch *scheme) EncapsulateDeterministically(
   263  	pk kem.PublicKey, seed []byte,
   264  ) (ct, ss []byte, err error) {
   265  	if len(seed) != sch.EncapsulationSeedSize() {
   266  		return nil, nil, kem.ErrSeedSize
   267  	}
   268  
   269  	h := sha3.NewShake256()
   270  	_, _ = h.Write(seed)
   271  	first := make([]byte, sch.first.EncapsulationSeedSize())
   272  	second := make([]byte, sch.second.EncapsulationSeedSize())
   273  	_, _ = h.Read(first)
   274  	_, _ = h.Read(second)
   275  
   276  	pub, ok := pk.(*publicKey)
   277  	if !ok {
   278  		return nil, nil, kem.ErrTypeMismatch
   279  	}
   280  
   281  	ct1, ss1, err := sch.first.EncapsulateDeterministically(pub.first, first)
   282  	if err != nil {
   283  		return nil, nil, err
   284  	}
   285  	ct2, ss2, err := sch.second.EncapsulateDeterministically(pub.second, second)
   286  	if err != nil {
   287  		return nil, nil, err
   288  	}
   289  	return append(ct1, ct2...), append(ss1, ss2...), nil
   290  }
   291  
   292  func (sch *scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
   293  	if len(ct) != sch.CiphertextSize() {
   294  		return nil, kem.ErrCiphertextSize
   295  	}
   296  
   297  	priv, ok := sk.(*privateKey)
   298  	if !ok {
   299  		return nil, kem.ErrTypeMismatch
   300  	}
   301  
   302  	firstSize := sch.first.CiphertextSize()
   303  	ss1, err := sch.first.Decapsulate(priv.first, ct[:firstSize])
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  	ss2, err := sch.second.Decapsulate(priv.second, ct[firstSize:])
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  	return append(ss1, ss2...), nil
   312  }
   313  
   314  func (sch *scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
   315  	if len(buf) != sch.PublicKeySize() {
   316  		return nil, kem.ErrPubKeySize
   317  	}
   318  	firstSize := sch.first.PublicKeySize()
   319  	pk1, err := sch.first.UnmarshalBinaryPublicKey(buf[:firstSize])
   320  	if err != nil {
   321  		return nil, err
   322  	}
   323  	pk2, err := sch.second.UnmarshalBinaryPublicKey(buf[firstSize:])
   324  	if err != nil {
   325  		return nil, err
   326  	}
   327  	return &publicKey{sch, pk1, pk2}, nil
   328  }
   329  
   330  func (sch *scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
   331  	if len(buf) != sch.PrivateKeySize() {
   332  		return nil, kem.ErrPrivKeySize
   333  	}
   334  	firstSize := sch.first.PrivateKeySize()
   335  	sk1, err := sch.first.UnmarshalBinaryPrivateKey(buf[:firstSize])
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	sk2, err := sch.second.UnmarshalBinaryPrivateKey(buf[firstSize:])
   340  	if err != nil {
   341  		return nil, err
   342  	}
   343  	return &privateKey{sch, sk1, sk2}, nil
   344  }
   345  

View as plain text