mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-07-31 20:11:23 +00:00
ECKey: Factor out findRecoveryId() from signMessage().
This commit is contained in:
committed by
Andreas Schildbach
parent
a5aac0f4b7
commit
a6fd71b767
@@ -865,17 +865,7 @@ public class ECKey implements EncryptableItem {
|
||||
byte[] data = formatMessageForSigning(message);
|
||||
Sha256Hash hash = Sha256Hash.twiceOf(data);
|
||||
ECDSASignature sig = sign(hash, aesKey);
|
||||
// Now we have to work backwards to figure out the recId needed to recover the signature.
|
||||
int recId = -1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ECKey k = ECKey.recoverFromSignature(i, sig, hash, isCompressed());
|
||||
if (k != null && k.pub.equals(pub)) {
|
||||
recId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (recId == -1)
|
||||
throw new RuntimeException("Could not construct a recoverable key. This should never happen.");
|
||||
byte recId = findRecoveryId(hash, sig);
|
||||
int headerByte = recId + 27 + (isCompressed() ? 4 : 0);
|
||||
byte[] sigData = new byte[65]; // 1 header + 32 bytes for R + 32 bytes for S
|
||||
sigData[0] = (byte)headerByte;
|
||||
@@ -940,6 +930,26 @@ public class ECKey implements EncryptableItem {
|
||||
throw new SignatureException("Signature did not match for message");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recovery ID, a byte with value between 0 and 3, inclusive, that specifies which of 4 possible
|
||||
* curve points was used to sign a message. This value is also referred to as "v".
|
||||
*
|
||||
* @throws RuntimeException if no recovery ID can be found.
|
||||
*/
|
||||
public byte findRecoveryId(Sha256Hash hash, ECDSASignature sig) {
|
||||
byte recId = -1;
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
ECKey k = ECKey.recoverFromSignature(i, sig, hash, isCompressed());
|
||||
if (k != null && k.pub.equals(pub)) {
|
||||
recId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (recId == -1)
|
||||
throw new RuntimeException("Could not construct a recoverable key. This should never happen.");
|
||||
return recId;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given the components of a signature and a selector value, recover and return the public key
|
||||
* that generated the signature according to the algorithm in SEC1v2 section 4.1.6.</p>
|
||||
|
@@ -239,6 +239,52 @@ public class ECKeyTest {
|
||||
assertEquals(expectedAddress, gotAddress);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findRecoveryId() {
|
||||
ECKey key = new ECKey();
|
||||
String message = "Hello World!";
|
||||
Sha256Hash hash = Sha256Hash.of(message.getBytes());
|
||||
ECKey.ECDSASignature sig = key.sign(hash);
|
||||
key = ECKey.fromPublicOnly(key.getPubKeyPoint());
|
||||
|
||||
List<Byte> possibleRecIds = Lists.newArrayList((byte) 0, (byte) 1, (byte) 2, (byte) 3);
|
||||
byte recId = key.findRecoveryId(hash, sig);
|
||||
assertTrue(possibleRecIds.contains(recId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyRecoveryTestVector() {
|
||||
// a test that exercises key recovery with findRecoveryId() on a test vector
|
||||
// test vector from https://crypto.stackexchange.com/a/41339
|
||||
ECKey key = ECKey.fromPrivate(
|
||||
new BigInteger("ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f", 16));
|
||||
String message = "Maarten Bodewes generated this test vector on 2016-11-08";
|
||||
Sha256Hash hash = Sha256Hash.of(message.getBytes());
|
||||
ECKey.ECDSASignature sig = key.sign(hash);
|
||||
key = ECKey.fromPublicOnly(key.getPubKeyPoint());
|
||||
|
||||
byte recId = key.findRecoveryId(hash, sig);
|
||||
byte expectedRecId = 0;
|
||||
assertEquals(recId, expectedRecId);
|
||||
|
||||
ECKey pubKey = ECKey.fromPublicOnly(key.getPubKeyPoint());
|
||||
ECKey recoveredKey = ECKey.recoverFromSignature(recId, sig, hash, true);
|
||||
assertEquals(recoveredKey, pubKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyRecoveryWithFindRecoveryId() throws Exception {
|
||||
ECKey key = new ECKey();
|
||||
String message = "Hello World!";
|
||||
Sha256Hash hash = Sha256Hash.of(message.getBytes());
|
||||
ECKey.ECDSASignature sig = key.sign(hash);
|
||||
|
||||
byte recId = key.findRecoveryId(hash, sig);
|
||||
ECKey pubKey = ECKey.fromPublicOnly(key.getPubKeyPoint());
|
||||
ECKey recoveredKey = ECKey.recoverFromSignature(recId, sig, hash, true);
|
||||
assertEquals(recoveredKey, pubKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyRecovery() throws Exception {
|
||||
ECKey key = new ECKey();
|
||||
|
Reference in New Issue
Block a user