Common MPC Pitfalls

MP-SPDZ MAC-check leakage under multithreading

In MP-SPDZ, the concrete synchronization point is Commit_And_Open_, the helper used by the MAC check to commit to local check values and then open them. Before the fix, each thread ran this helper independently. There was no coordinator shared across concurrent MAC checks, so one stalled check did not block another thread using the same global MAC key (source):

 1// FILE: Tools/Subroutines.cpp — MP-SPDZ (vulnerable, before 6a42453)
 2void Commit_And_Open_(vector<octetStream>& datas, const Player& P)
 3{
 4  vector<octetStream> Comm_data(P.num_players());
 5  vector<octetStream> Open_data(P.num_players());
 6
 7  Commit(Comm_data[P.my_num()], Open_data[P.my_num()], datas[P.my_num()],
 8      P.my_num());
 9  P.Broadcast_Receive(Comm_data);
10
11  P.Broadcast_Receive(Open_data);
12
13  for (int i = 0; i < P.num_players(); i++)
14    { if (i != P.my_num())
15        { if (!Open(datas[i], Comm_data[i], Open_data[i], i))
16             { throw invalid_commitment(); }
17        }
18    }
19}

The Rushing at SPDZ paper cites commits 6a42453 and b86f29b as the MP-SPDZ fix. The final version passes a shared Coordinator into Commit_And_Open_, waits before the opening phase, validates every opening, and only then calls coordinator.finished() (source):

 1// FILE: Tools/Subroutines.cpp — MP-SPDZ (fixed, commit b86f29b)
 2void Commit_And_Open_(vector<octetStream>& datas, const Player& P,
 3        Coordinator& coordinator)
 4{
 5  vector<octetStream> Comm_data(P.num_players());
 6  vector<octetStream> Open_data(P.num_players());
 7
 8  Commit(Comm_data[P.my_num()], Open_data[P.my_num()], datas[P.my_num()],
 9      P.my_num());
10  P.Broadcast_Receive(Comm_data);
11
12  coordinator.wait(P.get_id());
13  P.Broadcast_Receive(Open_data);
14
15  for (int i = 0; i < P.num_players(); i++)
16    { if (i != P.my_num())
17        { if (!Open(datas[i], Comm_data[i], Open_data[i], i))
18             { throw invalid_commitment(); }
19        }
20    }
21
22  coordinator.finished();
23}

Holding the coordinator until validation completes serializes the MAC-check opening path: a stalled or invalid MAC check prevents other threads from continuing under the same key.