3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-07 06:44:16 +00:00

Use compressed pubkeys by default. Resolves issue 111.

This commit is contained in:
Mike Hearn 2013-01-09 23:45:04 +01:00
parent 0bdfa7b635
commit d268270d7b
2 changed files with 19 additions and 17 deletions

View File

@ -45,7 +45,6 @@ import static com.google.common.base.Preconditions.checkArgument;
// TODO: This class is quite a mess by now. Once users are migrated away from Java serialization for the wallets,
// refactor this to have better internal layout and a more consistent API.
// TODO: Properly/completely support compressed pubkeys and use them by default.
/**
* Represents an elliptic curve keypair that we own and can use for signing transactions. Currently,
@ -58,9 +57,6 @@ public class ECKey implements Serializable {
private static final SecureRandom secureRandom;
private static final long serialVersionUID = -728224901792295832L;
/** How many bytes a Bitcoin public key is: 65, that is, two 32 byte co-ordinates plus a one byte header. */
public static final int PUBLIC_KEY_LENGTH = 65;
static {
// All clients must agree on the curve to use by agreement. Bitcoin uses secp256k1.
X9ECParameters params = SECNamedCurves.getByName("secp256k1");
@ -80,7 +76,10 @@ public class ECKey implements Serializable {
// Transient because it's calculated on demand.
transient private byte[] pubKeyHash;
/** Generates an entirely new keypair. */
/**
* Generates an entirely new keypair. Point compression is used so the resulting public key will be 33 bytes
* (32 for the co-ordinate and 1 byte to represent the y bit).
*/
public ECKey() {
ECKeyPairGenerator generator = new ECKeyPairGenerator();
ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(ecParams, secureRandom);
@ -89,8 +88,12 @@ public class ECKey implements Serializable {
ECPrivateKeyParameters privParams = (ECPrivateKeyParameters) keypair.getPrivate();
ECPublicKeyParameters pubParams = (ECPublicKeyParameters) keypair.getPublic();
priv = privParams.getD();
// The public key is an encoded point on the elliptic curve. It has no meaning independent of the curve.
pub = pubParams.getQ().getEncoded();
// Unfortunately Bouncy Castle does not let us explicitly change a point to be compressed, even though it
// could easily do so. We must re-build it here so the ECPoints withCompression flag can be set to true.
ECPoint uncompressed = pubParams.getQ();
ECPoint compressed = new ECPoint.Fp(ecParams.getCurve(), uncompressed.getX(), uncompressed.getY(), true);
pub = compressed.getEncoded();
creationTimeSeconds = Utils.now().getTime() / 1000;
}
@ -103,7 +106,7 @@ public class ECKey implements Serializable {
}
/**
* Output this ECKey as an ASN.1 encoded private key, as understood by OpenSSL or used by the BitCoin reference
* Output this ECKey as an ASN.1 encoded private key, as understood by OpenSSL or used by the Bitcoin reference
* implementation in its wallet storage format.
*/
public byte[] toASN1() {
@ -160,8 +163,8 @@ public class ECKey implements Serializable {
/**
* Creates an ECKey given only the private key bytes. This is the same as using the BigInteger constructor, but
* is more convenient if you are importing a key from elsewhere. The public key will be automatically derived
* from the private key.
* is more convenient if you are importing a key from elsewhere. If not provided the public key will be
* automatically derived from the private key.
*/
public ECKey(byte[] privKeyBytes, byte[] pubKey) {
this(privKeyBytes == null ? null : new BigInteger(1, privKeyBytes), pubKey);
@ -191,10 +194,10 @@ public class ECKey implements Serializable {
}
/**
* Returns whether this key is using the compressed form or not. Compressed pubkeys are only 35 bytes, not 64.
* Returns whether this key is using the compressed form or not. Compressed pubkeys are only 33 bytes, not 64.
*/
public boolean isCompressed() {
return pub.length == 35;
return pub.length == 33;
}
public String toString() {
@ -480,9 +483,9 @@ public class ECKey implements Serializable {
// Q = mi(r) * (sR - eG)
//
// Where mi(x) is the modular multiplicative inverse. We transform this into the following:
// Q = (mi(r) * s * R) + (mi(r) * -e * G)
// Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n), and + is the EC
// group operator.
// Q = (mi(r) * s ** R) + (mi(r) * -e ** G)
// Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation
// ** is point multiplication and + is point addition (the EC group operator).
//
// We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive
// inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8.

View File

@ -165,8 +165,7 @@ public class ECKeyTest {
key = new ECKey(null, key.getPubKey());
boolean found = false;
for (int i = 0; i < 4; i++) {
ECKey key2 = ECKey.recoverFromSignature(i, sig, hash, false);
assertNotNull("Key recovery did not work", key2);
ECKey key2 = ECKey.recoverFromSignature(i, sig, hash, true);
if (key.equals(key2)) {
found = true;
break;