Skip to content

Commit

Permalink
Merge pull request #301 from /issues/300
Browse files Browse the repository at this point in the history
Fixed 65bit public key issue
  • Loading branch information
meywood authored Jun 26, 2024
2 parents 3223936 + 8726ebc commit 7ac9899
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
25 changes: 22 additions & 3 deletions src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.syntifi.crypto.key;

import com.casper.sdk.model.key.AlgorithmTag;
import com.syntifi.crypto.key.encdec.Hex;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -77,7 +78,7 @@ public void writePublicKey(final Writer writer) throws IOException {
public Boolean verify(byte[] message, byte[] signature) {

//We need the Public key's short key
byte[] keyToFind = (getKey().length > 33) ? getShortKey(getKey()) : getKey();
byte[] keyToFind = (getKey().length > AlgorithmTag.SECP256K1.getLength()) ? getShortKey(getKey()) : getKey();

//Looping possible v's of the signature
for (int i = 27; i <= 34; i++) {
Expand All @@ -97,7 +98,7 @@ public Boolean verify(byte[] message, byte[] signature) {

if (recoveredKey != null) {

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

if (Arrays.equals(keyFromSignature, keyToFind)) {
return true;
Expand All @@ -120,7 +121,25 @@ public Boolean verify(byte[] message, byte[] signature) {
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, 32);
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);
}
}

}
72 changes: 72 additions & 0 deletions src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.syntifi.crypto.key;

import com.casper.sdk.model.key.PublicKey;
import com.syntifi.crypto.key.encdec.Hex;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
Expand All @@ -8,6 +9,7 @@
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
Expand Down Expand Up @@ -146,4 +148,74 @@ void signAndRecoverPublicKey_4() throws URISyntaxException, IOException {

}

@Test
void signAndRecoverPublicKey_5() throws GeneralSecurityException {

String publicKey = "02027fec2d969dd0779358c40abe2a772f309408348c2a1f413fddfe684a4287ba1a";
String signature = "2f26d3a896e5ad74bafc381455fc9bec808cea64b083b4a05e3dae43d80478820f59128c97bb50b52d5eba90eb29ec8dbd1b39fe6488bbc8c44a799e9a631878";
String hash = "92c983f3bb205b4f642f532dff837ebed56b19f11351da9181f6512e75a54a9b";

PublicKey key = new PublicKey();
key.createPublicKey(publicKey);

assert key.getPubKey().verify(Hex.decode(hash), Hex.decode(signature));

}

@Test
void signAndRecoverPublicKey_6() throws GeneralSecurityException {

String publicKey = "02024c5e3ba7b1da49cda950319aec914cd3c720fbec3dcf25aa4add631e28f70aa9";
String signature = "ade1d9902ec5520e0f52052b329cc62620ac5e84294729c559ce979fe0cf22aa29a8cef7a9d985851da01f68b4049ad9db3d310440cafcb3b5fe40ed6040aa1e";
String hash = "57a2fc930ab83f6bf5b3f1d7d5d1bd05ccd20dcbe3135f7c21a0553650d220e6";

PublicKey key = new PublicKey();
key.createPublicKey(publicKey);

assert key.getPubKey().verify(Hex.decode(hash), Hex.decode(signature));

}

@Test
void signAndRecoverPublicKey_7() throws GeneralSecurityException {

String publicKey = "0203b34ffdb855f8654f7f3805257844fe08d4055bcf75bbbb19b78463e34ba8b932";
String signature = "29d7ea92f1193c13c7ab5d90dfdfab75f52fd49047b9bb4fafc9962a7a1e0d2a36828d93d0d95080f53c625a2f2111dd86c37391f9a05a7ea5a1f2abba579476";
String hash = "3fa94f85c55a44a8afc2944914eb38720cc85d4b130809f8409a8c7e3e677298";

PublicKey key = new PublicKey();
key.createPublicKey(publicKey);

assert key.getPubKey().verify(Hex.decode(hash), Hex.decode(signature));

}

@Test
void signAndRecoverPublicKey_8() throws GeneralSecurityException {

String publicKey = "020287a38f11ac7aab689205912b981c21b80cf1efdd7541bd09cbe1e6ad6e8f188c";
String signature = "d1a796f1221e2256dbe85904e2c3d07be52c1482f8b3cfdce0bef0b6d4c5fc5537e3d8720054888eba9ddcb4c6ff388fabb5c09143000980e6af9096ee163524";
String hash = "1df13c9aaa8217657b7e5ec2442594735eeb4ca7e764877b3d2b593c3909d15f";

PublicKey key = new PublicKey();
key.createPublicKey(publicKey);

assert key.getPubKey().verify(Hex.decode(hash), Hex.decode(signature));

}

@Test
void signAndRecoverPublicKey_9() throws GeneralSecurityException {
String publicKey = "0202ea6c7f7f281078af87e79a3856d500da39d35743d8253c9bc1fce7b1da0a3536";
String signature = "c808c81f8db9a3a7364b0d884968c74427ace3fbd66cef9a8f0235e570b2774407071b63094446992e37c8f0e7d154bacd882d583fa2bfb043c884e445da56aa";
String hash = "e96cb427900710e89e39f3a69b8f576c8b5cb3085702f3c33c46fcbb115f1775";

PublicKey key = new PublicKey();
key.createPublicKey(publicKey);

assert key.getPubKey().verify(Hex.decode(hash), Hex.decode(signature));

}


}

0 comments on commit 7ac9899

Please sign in to comment.