kyber.go raw

   1  // Code generated from pkg.templ.go. DO NOT EDIT.
   2  
   3  // Package mlkem768 implements the IND-CCA2 secure key encapsulation mechanism
   4  // ML-KEM-768 as defined in FIPS203.
   5  package mlkem768
   6  
   7  import (
   8  	"bytes"
   9  	"crypto/subtle"
  10  	"io"
  11  
  12  	cryptoRand "crypto/rand"
  13  	"github.com/cloudflare/circl/internal/sha3"
  14  	"github.com/cloudflare/circl/kem"
  15  	cpapke "github.com/cloudflare/circl/pke/kyber/kyber768"
  16  )
  17  
  18  const (
  19  	// Size of seed for NewKeyFromSeed
  20  	KeySeedSize = cpapke.KeySeedSize + 32
  21  
  22  	// Size of seed for EncapsulateTo.
  23  	EncapsulationSeedSize = 32
  24  
  25  	// Size of the established shared key.
  26  	SharedKeySize = 32
  27  
  28  	// Size of the encapsulated shared key.
  29  	CiphertextSize = cpapke.CiphertextSize
  30  
  31  	// Size of a packed public key.
  32  	PublicKeySize = cpapke.PublicKeySize
  33  
  34  	// Size of a packed private key.
  35  	PrivateKeySize = cpapke.PrivateKeySize + cpapke.PublicKeySize + 64
  36  )
  37  
  38  // Type of a ML-KEM-768 public key
  39  type PublicKey struct {
  40  	pk *cpapke.PublicKey
  41  
  42  	hpk [32]byte // H(pk)
  43  }
  44  
  45  // Type of a ML-KEM-768 private key
  46  type PrivateKey struct {
  47  	sk  *cpapke.PrivateKey
  48  	pk  *cpapke.PublicKey
  49  	hpk [32]byte // H(pk)
  50  	z   [32]byte
  51  }
  52  
  53  // NewKeyFromSeed derives a public/private keypair deterministically
  54  // from the given seed.
  55  //
  56  // Panics if seed is not of length KeySeedSize.
  57  func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
  58  	var sk PrivateKey
  59  	var pk PublicKey
  60  
  61  	if len(seed) != KeySeedSize {
  62  		panic("seed must be of length KeySeedSize")
  63  	}
  64  
  65  	pk.pk, sk.sk = cpapke.NewKeyFromSeedMLKEM(seed[:cpapke.KeySeedSize])
  66  	sk.pk = pk.pk
  67  	copy(sk.z[:], seed[cpapke.KeySeedSize:])
  68  
  69  	// Compute H(pk)
  70  	var ppk [cpapke.PublicKeySize]byte
  71  	sk.pk.Pack(ppk[:])
  72  	h := sha3.New256()
  73  	h.Write(ppk[:])
  74  	h.Read(sk.hpk[:])
  75  	copy(pk.hpk[:], sk.hpk[:])
  76  
  77  	return &pk, &sk
  78  }
  79  
  80  // GenerateKeyPair generates public and private keys using entropy from rand.
  81  // If rand is nil, crypto/rand.Reader will be used.
  82  func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) {
  83  	var seed [KeySeedSize]byte
  84  	if rand == nil {
  85  		rand = cryptoRand.Reader
  86  	}
  87  	_, err := io.ReadFull(rand, seed[:])
  88  	if err != nil {
  89  		return nil, nil, err
  90  	}
  91  	pk, sk := NewKeyFromSeed(seed[:])
  92  	return pk, sk, nil
  93  }
  94  
  95  // EncapsulateTo generates a shared key and ciphertext that contains it
  96  // for the public key using randomness from seed and writes the shared key
  97  // to ss and ciphertext to ct.
  98  //
  99  // Panics if ss, ct or seed are not of length SharedKeySize, CiphertextSize
 100  // and EncapsulationSeedSize respectively.
 101  //
 102  // seed may be nil, in which case crypto/rand.Reader is used to generate one.
 103  func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) {
 104  	if seed == nil {
 105  		seed = make([]byte, EncapsulationSeedSize)
 106  		if _, err := cryptoRand.Read(seed[:]); err != nil {
 107  			panic(err)
 108  		}
 109  	} else {
 110  		if len(seed) != EncapsulationSeedSize {
 111  			panic("seed must be of length EncapsulationSeedSize")
 112  		}
 113  	}
 114  
 115  	if len(ct) != CiphertextSize {
 116  		panic("ct must be of length CiphertextSize")
 117  	}
 118  
 119  	if len(ss) != SharedKeySize {
 120  		panic("ss must be of length SharedKeySize")
 121  	}
 122  
 123  	var m [32]byte
 124  	copy(m[:], seed)
 125  
 126  	// (K', r) = G(m ‖ H(pk))
 127  	var kr [64]byte
 128  	g := sha3.New512()
 129  	g.Write(m[:])
 130  	g.Write(pk.hpk[:])
 131  	g.Read(kr[:])
 132  
 133  	// c = Kyber.CPAPKE.Enc(pk, m, r)
 134  	pk.pk.EncryptTo(ct, m[:], kr[32:])
 135  
 136  	copy(ss, kr[:SharedKeySize])
 137  }
 138  
 139  // DecapsulateTo computes the shared key which is encapsulated in ct
 140  // for the private key.
 141  //
 142  // Panics if ct or ss are not of length CiphertextSize and SharedKeySize
 143  // respectively.
 144  func (sk *PrivateKey) DecapsulateTo(ss, ct []byte) {
 145  	if len(ct) != CiphertextSize {
 146  		panic("ct must be of length CiphertextSize")
 147  	}
 148  
 149  	if len(ss) != SharedKeySize {
 150  		panic("ss must be of length SharedKeySize")
 151  	}
 152  
 153  	// m' = Kyber.CPAPKE.Dec(sk, ct)
 154  	var m2 [32]byte
 155  	sk.sk.DecryptTo(m2[:], ct)
 156  
 157  	// (K'', r') = G(m' ‖ H(pk))
 158  	var kr2 [64]byte
 159  	g := sha3.New512()
 160  	g.Write(m2[:])
 161  	g.Write(sk.hpk[:])
 162  	g.Read(kr2[:])
 163  
 164  	// c' = Kyber.CPAPKE.Enc(pk, m', r')
 165  	var ct2 [CiphertextSize]byte
 166  	sk.pk.EncryptTo(ct2[:], m2[:], kr2[32:])
 167  
 168  	var ss2 [SharedKeySize]byte
 169  
 170  	// Compute shared secret in case of rejection: ss₂ = PRF(z ‖ c)
 171  	prf := sha3.NewShake256()
 172  	prf.Write(sk.z[:])
 173  	prf.Write(ct[:CiphertextSize])
 174  	prf.Read(ss2[:])
 175  
 176  	// Set ss2 to the real shared secret if c = c'.
 177  	subtle.ConstantTimeCopy(
 178  		subtle.ConstantTimeCompare(ct, ct2[:]),
 179  		ss2[:],
 180  		kr2[:SharedKeySize],
 181  	)
 182  
 183  	copy(ss, ss2[:])
 184  }
 185  
 186  // Packs sk to buf.
 187  //
 188  // Panics if buf is not of size PrivateKeySize.
 189  func (sk *PrivateKey) Pack(buf []byte) {
 190  	if len(buf) != PrivateKeySize {
 191  		panic("buf must be of length PrivateKeySize")
 192  	}
 193  
 194  	sk.sk.Pack(buf[:cpapke.PrivateKeySize])
 195  	buf = buf[cpapke.PrivateKeySize:]
 196  	sk.pk.Pack(buf[:cpapke.PublicKeySize])
 197  	buf = buf[cpapke.PublicKeySize:]
 198  	copy(buf, sk.hpk[:])
 199  	buf = buf[32:]
 200  	copy(buf, sk.z[:])
 201  }
 202  
 203  // Unpacks sk from buf.
 204  //
 205  // Panics if buf is not of size PrivateKeySize.
 206  //
 207  // Returns an error if buf is not of size PrivateKeySize, or private key
 208  // doesn't pass the ML-KEM decapsulation key check.
 209  func (sk *PrivateKey) Unpack(buf []byte) error {
 210  	if len(buf) != PrivateKeySize {
 211  		return kem.ErrPrivKeySize
 212  	}
 213  
 214  	sk.sk = new(cpapke.PrivateKey)
 215  	sk.sk.Unpack(buf[:cpapke.PrivateKeySize])
 216  	buf = buf[cpapke.PrivateKeySize:]
 217  	sk.pk = new(cpapke.PublicKey)
 218  	sk.pk.Unpack(buf[:cpapke.PublicKeySize])
 219  	var hpk [32]byte
 220  	h := sha3.New256()
 221  	h.Write(buf[:cpapke.PublicKeySize])
 222  	h.Read(hpk[:])
 223  	buf = buf[cpapke.PublicKeySize:]
 224  	copy(sk.hpk[:], buf[:32])
 225  	copy(sk.z[:], buf[32:])
 226  	if !bytes.Equal(hpk[:], sk.hpk[:]) {
 227  		return kem.ErrPrivKey
 228  	}
 229  	return nil
 230  }
 231  
 232  // Packs pk to buf.
 233  //
 234  // Panics if buf is not of size PublicKeySize.
 235  func (pk *PublicKey) Pack(buf []byte) {
 236  	if len(buf) != PublicKeySize {
 237  		panic("buf must be of length PublicKeySize")
 238  	}
 239  
 240  	pk.pk.Pack(buf)
 241  }
 242  
 243  // Unpacks pk from buf.
 244  //
 245  // Returns an error if buf is not of size PublicKeySize, or the public key
 246  // is not normalized.
 247  func (pk *PublicKey) Unpack(buf []byte) error {
 248  	if len(buf) != PublicKeySize {
 249  		return kem.ErrPubKeySize
 250  	}
 251  
 252  	pk.pk = new(cpapke.PublicKey)
 253  	if err := pk.pk.UnpackMLKEM(buf); err != nil {
 254  		return err
 255  	}
 256  
 257  	// Compute cached H(pk)
 258  	h := sha3.New256()
 259  	h.Write(buf)
 260  	h.Read(pk.hpk[:])
 261  
 262  	return nil
 263  }
 264  
 265  // Boilerplate down below for the KEM scheme API.
 266  
 267  type scheme struct{}
 268  
 269  var sch kem.Scheme = &scheme{}
 270  
 271  // Scheme returns a KEM interface.
 272  func Scheme() kem.Scheme { return sch }
 273  
 274  func (*scheme) Name() string               { return "ML-KEM-768" }
 275  func (*scheme) PublicKeySize() int         { return PublicKeySize }
 276  func (*scheme) PrivateKeySize() int        { return PrivateKeySize }
 277  func (*scheme) SeedSize() int              { return KeySeedSize }
 278  func (*scheme) SharedKeySize() int         { return SharedKeySize }
 279  func (*scheme) CiphertextSize() int        { return CiphertextSize }
 280  func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
 281  
 282  func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
 283  func (pk *PublicKey) Scheme() kem.Scheme  { return sch }
 284  
 285  func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
 286  	var ret [PrivateKeySize]byte
 287  	sk.Pack(ret[:])
 288  	return ret[:], nil
 289  }
 290  
 291  func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
 292  	oth, ok := other.(*PrivateKey)
 293  	if !ok {
 294  		return false
 295  	}
 296  	if sk.pk == nil && oth.pk == nil {
 297  		return true
 298  	}
 299  	if sk.pk == nil || oth.pk == nil {
 300  		return false
 301  	}
 302  	if !bytes.Equal(sk.hpk[:], oth.hpk[:]) ||
 303  		subtle.ConstantTimeCompare(sk.z[:], oth.z[:]) != 1 {
 304  		return false
 305  	}
 306  	return sk.sk.Equal(oth.sk)
 307  }
 308  
 309  func (pk *PublicKey) Equal(other kem.PublicKey) bool {
 310  	oth, ok := other.(*PublicKey)
 311  	if !ok {
 312  		return false
 313  	}
 314  	if pk.pk == nil && oth.pk == nil {
 315  		return true
 316  	}
 317  	if pk.pk == nil || oth.pk == nil {
 318  		return false
 319  	}
 320  	return bytes.Equal(pk.hpk[:], oth.hpk[:])
 321  }
 322  
 323  func (sk *PrivateKey) Public() kem.PublicKey {
 324  	pk := new(PublicKey)
 325  	pk.pk = sk.pk
 326  	copy(pk.hpk[:], sk.hpk[:])
 327  	return pk
 328  }
 329  
 330  func (pk *PublicKey) MarshalBinary() ([]byte, error) {
 331  	var ret [PublicKeySize]byte
 332  	pk.Pack(ret[:])
 333  	return ret[:], nil
 334  }
 335  
 336  func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
 337  	return GenerateKeyPair(cryptoRand.Reader)
 338  }
 339  
 340  func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
 341  	if len(seed) != KeySeedSize {
 342  		panic(kem.ErrSeedSize)
 343  	}
 344  	return NewKeyFromSeed(seed[:])
 345  }
 346  
 347  func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
 348  	ct = make([]byte, CiphertextSize)
 349  	ss = make([]byte, SharedKeySize)
 350  
 351  	pub, ok := pk.(*PublicKey)
 352  	if !ok {
 353  		return nil, nil, kem.ErrTypeMismatch
 354  	}
 355  	pub.EncapsulateTo(ct, ss, nil)
 356  	return
 357  }
 358  
 359  func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (
 360  	ct, ss []byte, err error) {
 361  	if len(seed) != EncapsulationSeedSize {
 362  		return nil, nil, kem.ErrSeedSize
 363  	}
 364  
 365  	ct = make([]byte, CiphertextSize)
 366  	ss = make([]byte, SharedKeySize)
 367  
 368  	pub, ok := pk.(*PublicKey)
 369  	if !ok {
 370  		return nil, nil, kem.ErrTypeMismatch
 371  	}
 372  	pub.EncapsulateTo(ct, ss, seed)
 373  	return
 374  }
 375  
 376  func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
 377  	if len(ct) != CiphertextSize {
 378  		return nil, kem.ErrCiphertextSize
 379  	}
 380  
 381  	priv, ok := sk.(*PrivateKey)
 382  	if !ok {
 383  		return nil, kem.ErrTypeMismatch
 384  	}
 385  	ss := make([]byte, SharedKeySize)
 386  	priv.DecapsulateTo(ss, ct)
 387  	return ss, nil
 388  }
 389  
 390  func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
 391  	var ret PublicKey
 392  	if err := ret.Unpack(buf); err != nil {
 393  		return nil, err
 394  	}
 395  	return &ret, nil
 396  }
 397  
 398  func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
 399  	if len(buf) != PrivateKeySize {
 400  		return nil, kem.ErrPrivKeySize
 401  	}
 402  	var ret PrivateKey
 403  	if err := ret.Unpack(buf); err != nil {
 404  		return nil, err
 405  	}
 406  	return &ret, nil
 407  }
 408