<p>Mileage may vary with this answer. The short answer is probably no when using libbitcoin.  </p>

<p>Rationale: Over a year ago, when I experimented with sending funds to a uncompressed address using a signed transaction, the corresponding compressed keys could not be used to spend the same funds, the opposite was also true. The balance was dependent upon the compression of a key. When receiving with funds with an uncompressed address, only use the associated uncompressed private key to spend.  Similarly, when receiving receiving with funds with a compressed address, only use the associated compressed private key to spend.      </p>

CC BY-SA 3.0
2016-10-01T07:56:42.763Z
Thank you! I am hoping to play with libbitcoin very soon. I am slightly uneasy at the phrase 'uncompressed/compressed private key' but I understand what you mean :)
Sven Williamson
CC BY-SA 3.0
2016-10-01T09:00:28.077Z
You're talking about transactions. The original question is about signed messages.
Pieter Wuille
CC BY-SA 3.0
2016-09-30T22:58:35.820Z
2016-09-30T22:58:35.820Z
skaht
<p>The <code>bitcoinj</code> library's API offers a <code>signMessage</code> method of the <code>ECKey</code> class which returns a signature <code>(r,s)</code> as 65 bytes encoded as a Base64 string. The crunch of the encoding lies in the additional leading byte which allows key recovery (the 64 bytes of <code>(r,s)</code> alone are not enough for that purpose). In particular, the leading byte of the encoding includes information regarding the compression status of the signing key.</p>

<p>Now I assume this specific signature encoding was implemented for a very good reason, which I suspect is the fact that it is a standard encoding, present in many other bitcoin libraries and in core.</p>

<p>Now when verifying a signature through key recovery, the <code>verifyMessage</code> method ignores the compression status of the recovered key and simply ensures that the corresponding elliptic curve points match. Sure, this is a pretty good check, but why do we bother encoding the compression status of a signing key, if we are going to ignore it later? Is this the semantics other known libraries have adopted, or indeed core? I attach a small snippet for illustration:</p>

<pre><code>import org.bitcoinj.core.ECKey;
import java.security.SignatureException;

public class Test
{
  public static void main(String[] args)
  {
    String message = "some arbitrary message";

    ECKey k1 = new ECKey();      // random , compressed
    ECKey k2 = k1.decompress();

    // Signature (r,s) encoded as 65 bytes, with leading byte
    // allowing key recovery (including compression status)
    String sig1 = k1.signMessage(message);  
    String sig2 = k2.signMessage(message);  

    // compression status is encoded in signature =&gt; differing leading byte
    System.out.println(sig1);   // INgDhkt98Mme9m9AQ+nqtjyvjj ...
    System.out.println(sig2);   // HNgDhkt98Mme9m9AQ+nqtjyvjj ...

    // signatures are verified succesfully
    try
    {
      k1.verifyMessage(message, sig1);  // compressed case
    }
    catch(SignatureException e)
    {
      System.out.println("it should not happen");
    }

    try
    {
      k2.verifyMessage(message, sig2);  // uncompressed case
    }
    catch(SignatureException e)
    {
      System.out.println("it should not happen");
    }

    // in fact, compression status is ignored ...
    try
    {
      k1.verifyMessage(message, sig2);  // should it throw ?
    }
    catch(SignatureException e)
    {
      System.out.println("it does not happen");
    }

  }
}
</code></pre>

<public-key><bitcoinj><signature><ecdsa>
Should signature verification by key recovery ignore compression status?
Sven Williamson
# Should signature verification by key recovery ignore compression status?

(Asked by: username_0 on 2016-09-28)

The `bitcoinj` library's API offers a `signMessage` method of the `ECKey` class which returns a signature `(r,s)` as 65 bytes encoded as a Base64 string. The crunch of the encoding lies in the additional leading byte which allows key recovery (the 64 bytes of `(r,s)` alone are not enough for that purpose). In particular, the leading byte of the encoding includes information regarding the compression status of the signing key.

Now I assume this specific signature encoding was implemented for a very good reason, which I suspect is the fact that it is a standard encoding, present in many other bitcoin libraries and in core.

Now when verifying a signature through key recovery, the `verifyMessage` method ignores the compression status of the recovered key and simply ensures that the corresponding elliptic curve points match. Sure, this is a pretty good check, but why do we bother encoding the compression status of a signing key, if we are going to ignore it later? Is this the semantics other known libraries have adopted, or indeed core? I attach a small snippet for illustration:

```
import org.bitcoinj.core.ECKey;
import java.security.SignatureException;

public class Test
{
  public static void main(String[] args)
  {
    String message = "some arbitrary message";

    ECKey k1 = new ECKey();      // random , compressed
    ECKey k2 = k1.decompress();

    // Signature (r,s) encoded as 65 bytes, with leading byte
    // allowing key recovery (including compression status)
    String sig1 = k1.signMessage(message);  
    String sig2 = k2.signMessage(message);  

    // compression status is encoded in signature => differing leading byte
    System.out.println(sig1);   // INgDhkt98Mme9m9AQ+nqtjyvjj ...
    System.out.println(sig2);   // HNgDhkt98Mme9m9AQ+nqtjyvjj ...

    // signatures are verified succesfully
    try
    {
      k1.verifyMessage(message, sig1);  // compressed case
    }
    catch(SignatureException e)
    {
      System.out.println("it should not happen");
    }

    try
    {
      k2.verifyMessage(message, sig2);  // uncompressed case
    }
    catch(SignatureException e)
    {
      System.out.println("it should not happen");
    }

    // in fact, compression status is ignored ...
    try
    {
      k1.verifyMessage(message, sig2);  // should it throw ?
    }
    catch(SignatureException e)
    {
      System.out.println("it does not happen");
    }

  }
}

```

**Tags:** public-key, bitcoinj, signature, ecdsa


---

## 1 answers

### Answer by username_1 on 2016-09-30. Score: 1 | Accepted answer

Mileage may vary with this answer. The short answer is probably no when using libbitcoin.

Rationale: Over a year ago, when I experimented with sending funds to a uncompressed address using a signed transaction, the corresponding compressed keys could not be used to spend the same funds, the opposite was also true. The balance was dependent upon the compression of a key. When receiving with funds with an uncompressed address, only use the associated uncompressed private key to spend. Similarly, when receiving receiving with funds with a compressed address, only use the associated compressed private key to spend.

> **Comments:**
> **username_0**: Thank you! I am hoping to play with libbitcoin very soon. I am slightly uneasy at the phrase 'uncompressed/compressed private key' but I understand what you mean :)  
> **username_2**: You're talking about transactions. The original question is about signed messages.  

---

