newPeerScheme

A second, independently constructed scheme instance — what a remote peer runs, in its own process, on its own device.

Why this is a hook at all. A card deal is not one object encrypting twice: DealSession holds private val scheme: CommutativeScheme and one key, one session per player, and the law the protocol rests on is therefore cross-instancealice.encrypt(bob.encrypt(m, b), a) == bob.encrypt(alice.encrypt(m, a), b) where alice and bob are different objects. Drawing every key from a single instance, as this suite did before #2311, tests the one arrangement that cannot fail. Textbook SRA has each player choose their own modulus; a scheme written that way — the natural first draft — passes every single-instance property here and produces garbage on the second layer of a real deal. Neither distinctKeysProduceDistinctCiphertexts nor round-trip catches it, because a single peer's encrypt/strip pair still inverts.

Non-nullable and abstract on purpose. An "my scheme cannot do this" opt-out would move the vacuity one level up, where it is harder to see; and a default of = newScheme() would let an implementor whose group parameters are per-instance never confront the question at all — the compiler puts this KDoc in front of them instead. A scheme that cannot agree with a second instance of itself cannot participate in a deal, and that must fail here rather than in production.

It returns an instance, never a key. The suite generates every key itself, from the instance that will apply it, so a fixture cannot hand back two keys minted by one scheme.

Called more than once per property. Every call must return a freshly constructed instance; the cross-peer properties assert pairwise referential distinctness and fail loudly on a cached one. They also assert the peers' single-layer ciphertexts differ, so a fixture that seeds two instances identically — distinct objects, identical keys, layers that cancel — reds instead of passing.

What this cannot detect. The suite can demand a second independently constructed instance; it cannot inspect how the subclass built it. A fixture that deliberately hands both instances the group parameters production would have each peer roll separately still passes. That is the residual, and it is one an implementor has to write on purpose.