diff --git a/handshake/kem.go b/handshake/kem.go index a8978a5b..94e9a296 100644 --- a/handshake/kem.go +++ b/handshake/kem.go @@ -45,17 +45,32 @@ func (kemMLKEM1024) Decapsulate(privkey, ciphertext []byte) ([]byte, error) { } // mlkem1024Keys is KEMMLKEM1024 for one handshake. It decapsulates with the -// static key the Credential holds expanded, rather than expanding it again from -// the seed noise hands back; any other private key is expanded as usual. +// keys it holds expanded, the static one from the Credential and the ephemeral +// one it generated, rather than expanding them again from the seeds noise hands +// back; any other private key is expanded as usual. type mlkem1024Keys struct { kemMLKEM1024 - static *mlkem.DecapsulationKey1024 - staticSeed []byte + static *mlkem.DecapsulationKey1024 + staticSeed []byte + ephemeral *mlkem.DecapsulationKey1024 + ephemeralSeed []byte +} + +func (k *mlkem1024Keys) GenerateKeypair(_ io.Reader) (noise.KEMKey, error) { + dk, err := mlkem.GenerateKey1024() + if err != nil { + return noise.KEMKey{}, fmt.Errorf("mlkem1024: GenerateKey: %w", err) + } + k.ephemeral, k.ephemeralSeed = dk, dk.Bytes() + return noise.KEMKey{Private: k.ephemeralSeed, Public: dk.EncapsulationKey().Bytes()}, nil } func (k *mlkem1024Keys) Decapsulate(privkey, ciphertext []byte) ([]byte, error) { - if k.static != nil && subtle.ConstantTimeCompare(privkey, k.staticSeed) == 1 { + switch { + case k.static != nil && subtle.ConstantTimeCompare(privkey, k.staticSeed) == 1: return k.static.Decapsulate(ciphertext) + case k.ephemeral != nil && subtle.ConstantTimeCompare(privkey, k.ephemeralSeed) == 1: + return k.ephemeral.Decapsulate(ciphertext) } return k.kemMLKEM1024.Decapsulate(privkey, ciphertext) }