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 }