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}