fix(MPC deadlock): give each RCOT consumer its own instance - #1173
fix(MPC deadlock): give each RCOT consumer its own instance#1173AdamDawidKrol wants to merge 2 commits into
Conversation
…dlock MPC preprocess shared one SharedRCOT across the try_join3 branches (ke / record_layer / vm). The flush barrier waits for all clones to flush, but the branches don't all flush in the same round, so a clone parked behind a sibling branch never arrives -> rendezvous deadlock. Give each consumer its own instance (same global delta) so every barrier rendezvous is independent. Signed-off-by: Adam Król <adam.dawid.krol@gmail.com>
sinui0
left a comment
There was a problem hiding this comment.
This introduces a subtle security flaw: the kos protocol gets instantiated with the same delta correlation and the receiver has the opportunity to re-use the same base OT setup. Our kos implementation does not do domain separation by instance, so I think this gives the receiver the opportunity to outright learn (fatal) or at least sample delta.
Two options:
- Add instance domain separation to the kos implementation
- Use independent instances (run base OT twice)
|
@sinui0 Thank you for the comment! I'll answer in a few days. |
|
@sinui0 I reproduced the attack you described as a test in mpz: AdamDawidKrol/mpz#1 But I've been trying to see how a malicious party actually accesses the data it needs, and I can't. The recovery reads the honest sender's COT keys ( Am I missing something? |
Each RCOT consumer now gets its own KOS instance (deadlock fix), but they all reuse one global delta. Give each logical consumer a distinct `instance_id` salt so the instances are domain-separated, closing the shared-delta leak flagged in review of tlsnotary/tlsn#1173. Ids are assigned explicitly per consumer so prover and verifier stay matched (sender id N pairs with receiver id N); proxy mode uses a single fixed id. Depends on the mpz salt (AdamDawidKrol/mpz#2), pulled via the [patch] block.
Each RCOT consumer now gets its own KOS instance (deadlock fix), but they all reuse one global delta. Give each logical consumer a distinct `instance_id` salt so the instances are domain-separated, closing the shared-delta leak flagged in review of tlsnotary/tlsn#1173. Ids are assigned explicitly per consumer so prover and verifier stay matched (sender id N pairs with receiver id N); proxy mode uses a single fixed id. Depends on the mpz salt (AdamDawidKrol/mpz#2), pulled via the [patch] block.
Demonstrates the attack from review of tlsnotary/tlsn#1173: a malicious KOS receiver runs two extensions under the same global `delta` and reuses the same base OT. With no per-instance domain separation the two runs derive identical extension columns, so at any column where the receiver's internal choice bits differ, XOR-ing the sender's (raw, correlated) keys yields `delta` exactly. Test only; no protocol change. Runs against stock KOS.
Each RCOT consumer now gets its own KOS instance (deadlock fix), but they all reuse one global delta. Give each logical consumer a distinct `instance_id` salt so the instances are domain-separated, closing the shared-delta leak flagged in review of tlsnotary/tlsn#1173. Ids are assigned explicitly per consumer so prover and verifier stay matched (sender id N pairs with receiver id N); proxy mode uses a single fixed id. Depends on the mpz salt (AdamDawidKrol/mpz#2), pulled via the [patch] block.
Addresses the review on this PR: each RCOT consumer gets its own KOS instance but they all share one global `delta`. Give each logical consumer a distinct `instance_id` (matched across prover and verifier: sender id N ↔ receiver id N; proxy uses a single fixed id) so the same-`delta` instances are domain-separated. Depends on the KOS `instance_id` change (privacy-ethereum/mpz#446). Until that lands in a release, the `[patch]` block temporarily points mpz at an alpha.6-compatible build of the same change.
|
Domain separation pushed (privacy-ethereum/mpz#446 + commit here) |
MPC
preprocess(crates/tlsn/src/deps/{prover,verifier}.rs) builds oneSharedRCOTand hands clones to the concurrenttry_join3branches (key-exchange / record-layer / vm). ASharedRCOTonly performs its single batched flush once all live clones reach the flush barrier — but the branches don't all flush in the same round, so a clone whoseflush()is parked behind a sibling branch never arrives. The barrier then waits forever (alive=N, arrived=1) → an intermittent deadlock during preprocessing.Fix:
Give each RCOT consumer its own
SharedRCOTinstance instead of clones of a shared one, so every barrier rendezvous is independent and can't wait on a clone parked in another branch. All senders keep using the same globaldelta.