mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-12 02:05:53 +00:00
Use compressed pubkeys by default. Resolves issue 111.
This commit is contained in:
parent
0bdfa7b635
commit
d268270d7b
@ -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,
|
// 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.
|
// 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,
|
* 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 SecureRandom secureRandom;
|
||||||
private static final long serialVersionUID = -728224901792295832L;
|
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 {
|
static {
|
||||||
// All clients must agree on the curve to use by agreement. Bitcoin uses secp256k1.
|
// All clients must agree on the curve to use by agreement. Bitcoin uses secp256k1.
|
||||||
X9ECParameters params = SECNamedCurves.getByName("secp256k1");
|
X9ECParameters params = SECNamedCurves.getByName("secp256k1");
|
||||||
@ -80,7 +76,10 @@ public class ECKey implements Serializable {
|
|||||||
// Transient because it's calculated on demand.
|
// Transient because it's calculated on demand.
|
||||||
transient private byte[] pubKeyHash;
|
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() {
|
public ECKey() {
|
||||||
ECKeyPairGenerator generator = new ECKeyPairGenerator();
|
ECKeyPairGenerator generator = new ECKeyPairGenerator();
|
||||||
ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(ecParams, secureRandom);
|
ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(ecParams, secureRandom);
|
||||||
@ -89,8 +88,12 @@ public class ECKey implements Serializable {
|
|||||||
ECPrivateKeyParameters privParams = (ECPrivateKeyParameters) keypair.getPrivate();
|
ECPrivateKeyParameters privParams = (ECPrivateKeyParameters) keypair.getPrivate();
|
||||||
ECPublicKeyParameters pubParams = (ECPublicKeyParameters) keypair.getPublic();
|
ECPublicKeyParameters pubParams = (ECPublicKeyParameters) keypair.getPublic();
|
||||||
priv = privParams.getD();
|
priv = privParams.getD();
|
||||||
// The public key is an encoded point on the elliptic curve. It has no meaning independent of the curve.
|
// Unfortunately Bouncy Castle does not let us explicitly change a point to be compressed, even though it
|
||||||
pub = pubParams.getQ().getEncoded();
|
// 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;
|
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.
|
* implementation in its wallet storage format.
|
||||||
*/
|
*/
|
||||||
public byte[] toASN1() {
|
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
|
* 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
|
* is more convenient if you are importing a key from elsewhere. If not provided the public key will be
|
||||||
* from the private key.
|
* automatically derived from the private key.
|
||||||
*/
|
*/
|
||||||
public ECKey(byte[] privKeyBytes, byte[] pubKey) {
|
public ECKey(byte[] privKeyBytes, byte[] pubKey) {
|
||||||
this(privKeyBytes == null ? null : new BigInteger(1, privKeyBytes), 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() {
|
public boolean isCompressed() {
|
||||||
return pub.length == 35;
|
return pub.length == 33;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -480,9 +483,9 @@ public class ECKey implements Serializable {
|
|||||||
// Q = mi(r) * (sR - eG)
|
// Q = mi(r) * (sR - eG)
|
||||||
//
|
//
|
||||||
// Where mi(x) is the modular multiplicative inverse. We transform this into the following:
|
// Where mi(x) is the modular multiplicative inverse. We transform this into the following:
|
||||||
// Q = (mi(r) * s * R) + (mi(r) * -e * G)
|
// 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
|
// Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation
|
||||||
// group operator.
|
// ** 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
|
// 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.
|
// inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8.
|
||||||
|
@ -165,8 +165,7 @@ public class ECKeyTest {
|
|||||||
key = new ECKey(null, key.getPubKey());
|
key = new ECKey(null, key.getPubKey());
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
ECKey key2 = ECKey.recoverFromSignature(i, sig, hash, false);
|
ECKey key2 = ECKey.recoverFromSignature(i, sig, hash, true);
|
||||||
assertNotNull("Key recovery did not work", key2);
|
|
||||||
if (key.equals(key2)) {
|
if (key.equals(key2)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user