¿Debe la verificación de firma mediante la recuperación de claves ignorar el estado de compresión?

La bitcoinjAPI de la biblioteca ofrece un signMessagemétodo de la ECKeyclase que devuelve una firma (r,s)de 65 bytes codificada como una cadena Base64. El problema de la codificación radica en el byte inicial adicional que permite la recuperación de la clave (los 64 bytes por (r,s)sí solos no son suficientes para ese propósito). En particular, el byte inicial de la codificación incluye información sobre el estado de compresión de la clave de firma.

Ahora asumo que esta codificación de firma específica se implementó por una muy buena razón, que sospecho es el hecho de que es una codificación estándar, presente en muchas otras bibliotecas de bitcoin y en el núcleo.

Ahora, al verificar una firma a través de la recuperación de clave, el verifyMessagemétodo ignora el estado de compresión de la clave recuperada y simplemente se asegura de que coincidan los puntos de la curva elíptica correspondiente. Claro, esta es una verificación bastante buena, pero ¿por qué nos molestamos en codificar el estado de compresión de una clave de firma, si vamos a ignorarlo más tarde? ¿Es esta la semántica que han adoptado otras bibliotecas conocidas, o de hecho la principal? Adjunto un pequeño fragmento para ilustración:

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");
    }

  }
}

Respuestas (1)

El kilometraje puede variar con esta respuesta. La respuesta corta es probablemente no cuando se usa libbitcoin.

Justificación: Hace más de un año, cuando experimenté con el envío de fondos a una dirección sin comprimir usando una transacción firmada, las claves comprimidas correspondientes no se podían usar para gastar los mismos fondos, también ocurría lo contrario. El equilibrio dependía de la compresión de una clave. Cuando reciba fondos con una dirección sin comprimir, solo use la clave privada sin comprimir asociada para gastar. Del mismo modo, cuando reciba fondos con una dirección comprimida, solo use la clave privada comprimida asociada para gastar.

¡Gracias! Espero jugar con libbitcoin muy pronto. Estoy un poco incómodo con la frase 'clave privada sin comprimir/comprimida' pero entiendo lo que quieres decir :)
Estás hablando de transacciones. La pregunta original es sobre mensajes firmados.