mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-24 22:58:32 +01:00
ECKey: Fix violation of equals/hashCode contract.
ECKey violates the equals/hashCode contract for Java objects. Objects that are equivalent via the equals method, _must_ have the same hash code. This is not the case for ECKeys when comparing the compressed and uncompressed forms of a public key. The implementation of the `equals` method defines these objects to be equivalent, but the hashCode method defined them to be distinct! Original implementation comes from commit640db52cf4
which contains this bug. [1] Note that the comment identifies the correct intent: > Public keys are random already so we can just use a part of them as the hashcode. Read from the start to > avoid picking up the type code (compressed vs uncompressed) which is tacked on the end. But the second sentence is incorrect. The first byte (index 0) is the type code (compressed vs. uncompressed), not “the end”. The code has since been refactored in commit9219d8a9b5
but the implementation is effectively identical. [2] The fix is simple: use the most-significant four bytes of the X-coordinate of the public key. [1](640db52cf4 (diff-b59ef8be77b9148b27a14be59762c0c5R353)
) [2](9219d8a9b5 (diff-1849449aac05f7e59de7ebd56efd7f43R1201)
)
This commit is contained in:
parent
2f14c76fb8
commit
1746be6e10
2 changed files with 11 additions and 4 deletions
|
@ -1219,10 +1219,7 @@ public class ECKey implements EncryptableItem {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Public keys are random already so we can just use a part of them as the hashcode. Read from the start to
|
||||
// avoid picking up the type code (compressed vs uncompressed) which is tacked on the end.
|
||||
byte[] bits = getPubKey();
|
||||
return Ints.fromBytes(bits[0], bits[1], bits[2], bits[3]);
|
||||
return pub.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -454,4 +454,14 @@ public class ECKeyTest {
|
|||
for (byte b : bytes) if (b != 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublicKeysAreEqual() {
|
||||
ECKey key = new ECKey();
|
||||
ECKey pubKey1 = ECKey.fromPublicOnly(key.getPubKeyPoint());
|
||||
assertTrue(pubKey1.isCompressed());
|
||||
ECKey pubKey2 = pubKey1.decompress();
|
||||
assertEquals(pubKey1, pubKey2);
|
||||
assertEquals(pubKey1.hashCode(), pubKey2.hashCode());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue