From f0f7874340344079a0da0a8bcfdc549a9d6d8d46 Mon Sep 17 00:00:00 2001 From: Carl Norburn Date: Thu, 27 Jun 2024 11:56:22 +0100 Subject: [PATCH] Fixed the 50% Secp problem when creating a public short key --- .../crypto/key/Secp256k1PublicKey.java | 28 ++++++------------- .../crypto/key/Secp256k1PublicKeyTests.java | 26 ++++++++++++++++- .../resources/secp256k1/private-padded.pem | 3 ++ 3 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 src/test/resources/secp256k1/private-padded.pem diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java index f63120c7..42ab4890 100644 --- a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java @@ -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; @@ -114,6 +114,10 @@ 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 @@ -121,25 +125,11 @@ 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, (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)); } } diff --git a/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java b/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java index a9b1a59f..b02687d4 100644 --- a/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java +++ b/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java @@ -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(); diff --git a/src/test/resources/secp256k1/private-padded.pem b/src/test/resources/secp256k1/private-padded.pem new file mode 100644 index 00000000..4dde15e7 --- /dev/null +++ b/src/test/resources/secp256k1/private-padded.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PRIVATE KEY----- +MC4CAQEEIGbGCLXUsZFyrJe4nAGW+V5Zd7z+AbccZ5SU3LBQi/Q6oAcGBSuBBAAK +-----END EC PRIVATE KEY-----