Skip to content

feat(prf): add support for EMS mode#1121

Open
th4s wants to merge 3 commits intomainfrom
feat/prf-ems-support
Open

feat(prf): add support for EMS mode#1121
th4s wants to merge 3 commits intomainfrom
feat/prf-ems-support

Conversation

@th4s
Copy link
Copy Markdown
Member

@th4s th4s commented Mar 9, 2026

This PR

  • adds support for EMS mode to our PRF.
  • relaxes the strict requirements on setting inputs depending on internal PRF state.

@th4s th4s requested review from sinui0 and themighty1 March 9, 2026 13:46
@sinui0
Copy link
Copy Markdown
Member

sinui0 commented Mar 10, 2026

@claude review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 10, 2026

Claude encountered an error —— View job


Reviewing PR #1121: feat(prf): add support for EMS mode

  • Gather context and read CLAUDE.md
  • Read PR diff and changed files
  • Analyze changes and provide review feedback

@heeckhau
Copy link
Copy Markdown
Member

@claude review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 10, 2026

Claude finished @heeckhau's task in 1m 49s —— View job


Reviewing PR #1121: feat(prf): add support for EMS mode

  • Gather context and read CLAUDE.md
  • Read PR diff and changed files
  • Analyze changes and provide review feedback

Summary

This PR adds Extended Master Secret (RFC 7627) support to the PRF implementation by:

  1. Renaming Mode → split into NetworkMode + MSMode — cleanly separates the network optimization concern (Normal vs Reduced) from the master secret derivation mode (Standard vs Extended).
  2. Renaming MpcPrfPrf — simpler name.
  3. Introducing PrfConfig — bundles NetworkMode and MSMode together.
  4. Adding set_session_hash() — new method for providing the session hash in EMS mode.
  5. Deleting prf/state.rs — the state machine was simplified and inlined into prf.rs.
  6. Relaxing input-setting requirementsset_client_random and set_server_random no longer enforce strict state ordering; the master secret seed is set conditionally based on MSMode.

Feedback

Overall: This is a well-structured change. The separation of NetworkMode and MSMode is clean, the EMS label/seed differences are correctly handled per RFC 7627, and tests cover all four combinations (Normal/Reduced × Standard/Extended). A few observations:


1. Potential panic in set_server_random — consider returning an error instead

prf.rs:151-153:

let client_random = self
    .client_random
    .expect("Client random should have been set by now");

Since this PR explicitly relaxes input-setting ordering requirements, the expect here is a latent panic if a caller sets the server random before the client random. Since set_server_random already returns Result<(), PrfError>, this could return a proper error instead.

Fix this →


2. MSMode::Standard guard in set_server_random — only sets MS seed for Standard mode

prf.rs:156-160:

if matches!(self.config.ms, MSMode::Standard) {
    let mut seed_ms = client_random.to_vec();
    seed_ms.extend_from_slice(&server_random);
    master_secret.set_start_seed(seed_ms);
}

This is correct — in EMS mode the session hash is the seed. But it might be worth a brief comment here explaining why the MS seed is skipped in EMS mode, since the relationship to set_session_hash() isn't immediately obvious from this code alone.


3. No enforcement that set_session_hash is called before flush in EMS mode

In set_session_hash (prf.rs:177-190), the session hash sets master_secret.set_start_seed(seed). However, if a caller forgets to call this in EMS mode, the start_seed_label will be None and flush() will panic when it hits expect("Start seed should have been set") in both normal.rs:83 and reduced.rs:106.

This isn't a regression (the Standard path has the same pattern), but since this PR is adding the EMS path, it would be a good time to consider returning errors from flush() instead of panicking on missing seeds. At minimum, a doc comment on set_session_hash noting it must be called before flush in EMS mode would help.


4. PrfConfig fields are pub — intentional?

config.rs:24-29:

pub struct PrfConfig {
    pub network: NetworkMode,
    pub ms: MSMode,
}

Both fields are pub and accessed directly (e.g., self.config.network, self.config.ms in prf.rs). Since PrfConfig already has a constructor, you might want pub(crate) visibility on the fields to keep the public API surface minimal. This is a minor style point — fine either way if direct field access from downstream is intended.


5. MSMode and NetworkMode don't derive PartialEq

config.rs:5,13: Neither enum derives PartialEq, which means the code uses matches!() for comparisons (e.g., matches!(self.config.ms, MSMode::Standard)). This works, but deriving PartialEq (and Eq) would be more idiomatic and enable == comparisons if needed in the future.


6. mpc-tls hardcodes MSMode::Standard

leader.rs:89 and follower.rs:67:

let prf = Prf::new(PrfConfig::new(config.prf, MSMode::Standard));

This is presumably intentional for this PR (EMS integration at the mpc-tls layer is future work), but worth noting that the mpc-tls Config struct only exposes NetworkMode (prf field). When EMS support is wired in, Config will need an MSMode field and the set_session_hash call path.


7. Test coverage is solid

  • All 4 mode combinations are tested at both the inner PrfFunction level (function.rs tests) and the outer Prf level (lib.rs tests).
  • A reference test against ring's PRF (test_prf_reference_ems_ms) validates correctness.
  • Benchmarks cover all 4 combinations.

Verdict

The implementation is correct and well-tested. The main actionable suggestion is replacing the expect in set_server_random with a proper error (point 1), since this PR explicitly aims to relax strict input ordering. The rest are minor style/documentation suggestions.


@th4s th4s force-pushed the feat/prf-ems-support branch from 25c70f3 to d1e3098 Compare March 11, 2026 10:40
@th4s th4s mentioned this pull request Mar 12, 2026
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.

3 participants