Pitfall

Rushing Adversary Copies an Honest Commitment

What can go wrong. In a commit-and-reveal protocol, each party sends a commitment during round 1 and opens it during round 2. If the commitment scheme does not bind each commitment to the identity of its opener (for example, by hashing in the party’s ID and session ID), a rushing adversary, one who observes honest parties’ messages before sending its own in the same round, can copy an honest party’s commitment byte-for-byte, then copy the opening during the reveal phase. Both parties end up revealing the same value.

Security implication. Consider a Blum coinflip: Alice and Bob commit to random bits $v_A, v_B$ and open to produce $v = v_A \oplus v_B$. A corrupt Bob who copies Alice’s commitment, then copies her opening, makes $v_B = v_A$, so the output is always $v_A \oplus v_A = 0$, the coin no longer flips. The same pattern breaks the SPDZ MAC-check sub-protocol in two-party settings over a characteristic-two field: when parties commit to their $z_i$ shares and an honest $P_1$’s commitment is copied, the reconstructed $z = z_1 + z_1 = 0$ and the MAC check passes for any opened value $a'$, defeating the integrity guarantee on every wire of the circuit.

How to avoid. Bind every commitment to its opener’s identity and to the session. Two standard constructions:

  • Hash-based commitment with opener ID and session ID: $c_i = H(\text{pid}_i \,\|\, \text{ssid} \,\|\, v_i \,\|\, r_i)$. A copied commitment has the wrong pid and cannot be reopened consistently.
  • Signed commitment: Contrary to the hash-based commitment, a signed commitment binds only the PID (through the signing key) and not the SSID. To bind both the party and the session, you may use one of the following:
    • Compute the signature $s = \text{Sign}_{\text{sk}_i}(\text{ssid} \,\|\, c)$, where $c$ is the commitment and $\text{sk}_i$ is the signing key tied to the party.
    • Include the session ID inside the commitment, $c_i = \text{Commit}(\text{ssid} \,\|\, v_i \,\|\, r_i)$, and sign it with a key bound to the party. Here the commitment provides the session binding and the key provides the party binding.
    • Use a signing key uniquely bound to both the party and the current session. Note that this is quite unusual in practice, as long-term signing keys are typically preferred.

Either construction prevents the rushing-adversary copy because the opener’s identity and the current session are now part of what the commitment binds to.

Example Fresco HashBasedCommitment (Issue #432, PR #433)

In the SPDZ protocol, parties hold additive shares of a global SPDZ MAC $[\alpha \cdot a]$ on every wire under a single 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(v_i \,\|\, r_i)$, with no opener identity in the hash input. Fresco does not implement SPDZ over binary fields, so the characteristic-2 single-MAC-check copy (where a copied $z_1$ gives $z = z_1 + z_1 = 0$) does not apply to it directly. Fresco is instead hit through the same commitment’s use in coin-tossing: a corrupt party copies an honest party’s seed commitment $H(s_i \,\|\, r_i)$ byte-for-byte and later copies the opening $(s_i, r_i)$, so the two identical seeds cancel in the XOR $s = s_1 \oplus \cdots \oplus s_n$. This strips the honest party’s entropy from the tossed coin, making it adversarially predictable and letting the corrupt party pass the batch MAC check on inconsistent values. 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}