Skip to content

fix randomized X25519MLKEM768 key share consistency - #415

Open
T1nyBear wants to merge 1 commit into
refraction-networking:masterfrom
T1nyBear:fix-randomized-mlkem-keyshare
Open

fix randomized X25519MLKEM768 key share consistency#415
T1nyBear wants to merge 1 commit into
refraction-networking:masterfrom
T1nyBear:fix-randomized-mlkem-keyshare

Conversation

@T1nyBear

@T1nyBear T1nyBear commented Sep 4, 2026

Copy link
Copy Markdown

Summary

generateRandomizedSpec currently decides independently whether to include X25519MLKEM768 in supported_groups and whether to include its initial key share.

This can produce two problematic combinations:

  1. X25519MLKEM768 is advertised without an initial key share. This is valid TLS 1.3, but allows a server to select the group through HelloRetryRequest, while the current uTLS HRR handler explicitly does not support selecting X25519MLKEM768 through HRR.

  2. X25519MLKEM768 is included in key_share without being present in supported_groups. TLS 1.3 explicitly forbids this: every KeyShareEntry must correspond to a group offered in supported_groups (RFC 9846 §4.3.8).

The existing HRR handler already assumes that if X25519MLKEM768 is enabled, its initial key share is always sent.

Change

Use a single randomized decision for both supported_groups and the initial key_share.

When randomized advertises X25519MLKEM768, it also includes its initial key share. Otherwise, neither is included.

The previous key-share random draw is still consumed to preserve the PRNG sequence for existing randomized seeds.

This preserves the randomized choice of whether to offer X25519MLKEM768, while:

  • preventing invalid supported_groups / key_share combinations;
  • preserving the invariant expected by the existing HRR handler;
  • avoiding the unsupported X25519MLKEM768 HRR path.

Future HRR support

If X25519MLKEM768 HRR support is implemented in the future, the decision to include its initial key share can be randomized again, but only when the group itself is advertised.

The result of the existing random draw can then be used instead of discarded, while the draw remains in the same key-share randomization branch.

For example:

includeX25519MLKEM768KeyShare := false
if r.FlipWeightedCoin(id.Weights.FirstKeyShare_Set_CurveP256) { // legacy setting, not used by default
	ks.KeyShares[0].Group = CurveP256
} else {
	if r.FlipWeightedCoin(id.Weights.KeyShare_Append_RandomGroups) {
		ks.KeyShares = append(ks.KeyShares, KeyShare{Group: CurveP256})
	}
	includeX25519MLKEM768KeyShare = r.FlipWeightedCoin(id.Weights.KeyShare_Append_RandomGroups)
}
if includeX25519MLKEM768 && includeX25519MLKEM768KeyShare {
	ks.KeyShares = append([]KeyShare{{Group: X25519MLKEM768}}, ks.KeyShares...)
}

Related

@T1nyBear
T1nyBear force-pushed the fix-randomized-mlkem-keyshare branch from 6efc1a5 to f2a1e52 Compare September 4, 2026 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant