Skip to content

Commit

Permalink
Fixed the 50% Secp problem when creating a public short key
Browse files Browse the repository at this point in the history
  • Loading branch information
stormeye2000 committed Jun 27, 2024
1 parent 9717acf commit f0f7874
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 20 deletions.
28 changes: 9 additions & 19 deletions src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public Boolean verify(byte[] message, byte[] signature) {

if (recoveredKey != null) {

final byte[] keyFromSignature = getRecoveredShortKey(recoveredKey.toByteArray());
final byte[] keyFromSignature = getShortKey(recoveredKey.toByteArray());

if (Arrays.equals(keyFromSignature, keyToFind)) {
return true;
Expand All @@ -114,32 +114,22 @@ public Boolean verify(byte[] message, byte[] signature) {

/**
* Gets a short key
* There's around a 50% chance the elliptical curve algo will generate a 65 byte
* public key instead of 66 byte.
* Luckily the algo pads the first byte as zero when this happens
* startBit determines this
*
* @param key the key as a byte array
* @return short key as byte array
*/
public static byte[] getShortKey(final byte[] key) {
final BigInteger pubKey = new BigInteger(key);
final String pubKeyPrefix = pubKey.testBit(0) ? "03" : "02";
final byte[] pubKeyBytes = Arrays.copyOfRange(key, 0, (AlgorithmTag.SECP256K1.getLength() - 1));
return Hex.decode(pubKeyPrefix + Hex.encode(pubKeyBytes));
}

/**
* There's around a 50% chance the elliptical curve algo will generate a 65 byte
* public key instead of 66 byte.
* Luckily the algo pads the first byte as zero when this happens
* Determine this and then return the byte array to be shortened
*
* @param key the key as a byte array
* @return short key as byte array
*/
public static byte[] getRecoveredShortKey(final byte[] key){
if (key[0] == (byte) 0) {
return getShortKey(Arrays.copyOfRange(key, 1, (key.length - 1)));
} else {
return getShortKey(key);
}
final int startBit = key[0] == (byte) 0 ? 1 : 0;

final byte[] pubKeyBytes = Arrays.copyOfRange(key, startBit, (AlgorithmTag.SECP256K1.getLength() - 1) + startBit);
return Hex.decode(pubKeyPrefix + Hex.encode(pubKeyBytes));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,31 @@ void verify_should_be_ok() throws URISyntaxException, IOException {
}

@Test
void signAndRecoverPublicKey_1() throws URISyntaxException, IOException {
void signAndRecoverPublicKeyWithPaddedPK() throws URISyntaxException, IOException {

//Get the private key
Secp256k1PrivateKey privKey = new Secp256k1PrivateKey();
String filePath = getResourcesKeyPath("secp256k1/private-padded.pem");
privKey.readPrivateKey(filePath);

//Check that the public key is padded with a 0 byte
assert privKey.getKeyPair().getPublicKey().toByteArray()[0] == (byte) 0;


//Derive the public key
Secp256k1PublicKey publicKey = (Secp256k1PublicKey) privKey.derivePublicKey();

String message = "bc81ca4de9b3a991a6514eddf0e994e0035c7ba58f333c4d7ba5dd18b4c9c547";

//Generate the signature
byte[] signature = privKey.sign(message.getBytes());

//Test
assert publicKey.verify(message.getBytes(), signature);

}
@Test
void signAndRecoverPublicKey_1() throws URISyntaxException, IOException {

//Get the private key
Secp256k1PrivateKey privKey = new Secp256k1PrivateKey();
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/secp256k1/private-padded.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIGbGCLXUsZFyrJe4nAGW+V5Zd7z+AbccZ5SU3LBQi/Q6oAcGBSuBBAAK
-----END EC PRIVATE KEY-----

0 comments on commit f0f7874

Please sign in to comment.