Skip to content

Multi-peer integration tests for keep-frost-net ECDH coordination (round-2 mutation kills) #543

Description

@kwsantiago

Follow-up to #417's round 2 (PR landing now). Mirrors the shape of #541 for the signing-module work.

What round 2 shipped

Unit tests on `keep-frost-net/src/ecdh.rs` killed 47 of 53 mutations that survived the baseline:

Function Before After
Pure helpers (derive_ecdh_session_id, compute_partial_ecdh, lagrange_coefficient, aggregate_ecdh_shares) 9 surviving 1 surviving
EcdhSession state machine + accessors 29 surviving 2 surviving
EcdhSessionManager lifecycle 15 surviving 0 surviving

Final: 63/110 caught (57%), up from 16/110 (15%).

What's still surviving in keep-frost-net/src/node/ecdh.rs (20 mutations)

All on the async coordination handlers, same shape as #541's signing-module survivors. They need multi-peer integration test infrastructure to kill.

Function Surviving mutations What that means
handle_ecdh_request 5 Responder gates: replay window check, peer-policy, participant-membership; multiple delete ! and ==/!= mutations on early-return predicates.
request_ecdh 10 Requester orchestration: match arms on EcdhComplete / EcdhFailed / Err, terminator predicates, the has_all_shares match guard.
handle_ecdh_complete 3 Final-secret delivery: subscriber notification + session-id equality check.
handle_ecdh_share 2 Share ingestion: full function "replace with Ok(())" and the share-index match.

Remaining 6 in keep-frost-net/src/ecdh.rs

Triaged but deliberately not chased:

  • aggregate_ecdh_shares line 96 (+=-=): equivalent on the single-party case because IDENTITY + p = IDENTITY - p produces points with the same x-only output. Distinguishing requires multi-party, same scope as the node/ecdh.rs survivors.
  • EcdhSession::state line 169 (>>=): off-by-one at the exact timeout boundary. Hitting it deterministically requires sub-nanosecond timing control.
  • EcdhSession::try_complete line 222 (-/): byte-index arithmetic on the Identifier serialization buffer. Both len-2=30 and len/2=16 index into a 32-byte buffer; for small share indices the high bytes are 0 in both positions.
  • shared_secret() accessor: 3 mutations on the return shape. The new `ecdh_session_shared_secret_returns_stored_value_only_after_completion` test kills the None and constant-leak mutations on the post-completion path; the pre-completion-None path is exercised by the same test.

Proposed approach

Same as #541 — an in-process multi-peer simulator that drives ECDH sessions without a real relay, covering:

  • 2-of-3 happy path (kills the "replace Result<()> with Ok(())" mutations because the absence of a real send on any handler breaks the round).
  • Replay window edge: a request just outside the window must be refused (kills the ==/!= mutations in handle_ecdh_request).
  • Failed completion → subscriber notification (kills the handle_ecdh_complete mutations).
  • Re-run `cargo mutants -p keep-frost-net --file keep-frost-net/src/node/ecdh.rs` and confirm survival rate drops materially.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmediumnostr-frostNostr FROST coordination protocolp3Lowest PrioritysecuritySecurity-related issues

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions