Common MPC Pitfalls

Fresco `HashBasedCommitment`

In the SPDZ protocol, parties hold BDOZ MACs $[\alpha \cdot a]$ on every wire under a global MAC key $\alpha$. To verify that a reconstructed value $a'$ is correct, each party computes $z_i = a' \cdot \alpha_i - (\alpha \cdot a)_i$, commits to $z_i$, and opens; if the reconstructed $z = \sum z_i \ne 0$, they abort. SPDZ also uses the same commitment scheme in coin-tossing and input-sharing subprotocols.

Fresco’s HashBasedCommitment hashed only the value and the randomness,with no opener identity in the input, allowing a malicious party to replay it. Pre-fix commit method (source):

 1// FILE: tools/commitment/src/main/java/dk/alexandra/fresco/tools/commitment/HashBasedCommitment.java
 2// aicis/fresco @ 2dc80dca (vulnerable, pre-PR #433)
 3
 4public byte[] commit(Drbg rand, byte[] value) {
 5  if (commitmentVal != null) {
 6    throw new IllegalStateException("Already committed");
 7  }
 8  // Sample a sufficient amount of random bits
 9  byte[] randomness = new byte[DIGEST_LENGTH];
10  rand.nextBytes(randomness);
11  // Construct an array to contain the bytes to hash
12  byte[] openingInfo = new byte[value.length + randomness.length];
13  System.arraycopy(value, 0, openingInfo, 0, value.length);
14  System.arraycopy(randomness, 0, openingInfo, value.length,
15      randomness.length);
16  commitmentVal = digest.digest(openingInfo);
17  return openingInfo;
18}

Each party’s commitment is $c_i = H(z_i \,\|\, r_i)$, with no opener identity in the hash input. In a two-party SPDZ MAC check over $\mathbb{F}_{2^k}$, a corrupt $P_2$ copies $P_1$’s commitment byte-for-byte, then copies the opening $(z_1, r_1)$. Because the field has characteristic 2, the reconstructed $z = z_1 + z_1 = 0$ and the MAC check passes regardless of what $a'$ was reconstructed. The fix (PR #433) added the committer’s party ID as the first input to the hash and required the opener to supply a matching ID at open time (source):

 1// FILE: tools/commitment/src/main/java/dk/alexandra/fresco/tools/commitment/HashBasedCommitment.java
 2// aicis/fresco @ fdada93b (fixed)
 3
 4public byte[] commit(int myId, Drbg rand, byte[] value) {
 5  if (commitmentVal != null) {
 6    throw new IllegalStateException("Already committed");
 7  }
 8  byte[] randomness = new byte[DIGEST_LENGTH];
 9  rand.nextBytes(randomness);
10  // Party ID is now the first ID_LENGTH bytes of the hashed input.
11  byte[] openingInfo = new byte[ID_LENGTH + value.length + randomness.length];
12  System.arraycopy(integerToBytes(myId), 0, openingInfo, 0, ID_LENGTH);
13  System.arraycopy(value, 0, openingInfo, ID_LENGTH, value.length);
14  System.arraycopy(randomness, 0, openingInfo, value.length + ID_LENGTH,
15      randomness.length);
16  commitmentVal = digest.digest(openingInfo);
17  return openingInfo;
18}