ScriptSig no valida con una firma aparentemente válida

Estoy tratando de construir transacciones sin procesar desde cero para mejorar mi comprensión. A modo de comparación, estoy usando la salida hexadecimal de https://coinb.in/ ya que puedo elegir Testnet allí.

Estoy tratando de construir una transacción P2PKH sin Segwit (por ahora) que debería usar este tx 577735da1fccf6df79eac9ff42049a7729703ec5506efeb1602bca99df3bafd2(índice 0) y enviar 6889990satoshi a mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB, la clave pública sin procesar de la dirección de entrada es034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073d

Entonces, para la transacción sin firmar que produce mi biblioteca 0100000001d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757000000002221034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073dffffffff0106226900000000001976a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac00000000, que coincide con lo que produce coinb.

Entonces, para generar la firma para el sigscript, uso el siguiente código:

def sign_transaction(self, secrets):
    """
    Sign all inputs of the transaction with
    a secret key.
    :param ECPrivKey[] secrets: a list of private keys corresponding to the inputs
    :return: Transaction Signed version of the transaction ready to be published
    """
    unsigned = bytes.fromhex(self.serialize_to_hex())
    message = sha256(sha256(unsigned))
    copy = deepcopy(self)
    inputs = self.__inputs
    for i in range(0, len(secrets)):
        sk = secrets[i]
        inp = inputs[i]
        sig = SignatureFactory.gen_ecdsa_signature_bytes(message, sk)
        copy.set_signature(sig)
        sigscript = sig.get_asn1_encoded() + OP_SIGHASH_ALL
        l = len(bytes.fromhex(sigscript))
        script = compact_size_int(l) + sigscript + inp.get_sig_script()
        copy.__inputs[i].set_sig_script(script)
    return copy

De manera informal, uso la salida hexadecimal de la transacción sin firmar, la convierto en bytes, ejecuto dos funciones hash sha256 y agrego el byte SIGHASH ('01')

Validé la firma producida y es válida, así que siento que hay algún problema con la serialización. Aquí está mi transacción después de firmarla:

0100000001d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757000000006a47304402207da5c1e2d7db828e415db1ae060d65e4a44de2b13b71c50be61d6c52da82425b022010da9abb70c7b6047b559c5c572f68e078d6ae78ba03dfd6aa1890e512e376760121034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073dffffffff0106226900000000001976a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac00000000

{"version": "01000000", "flag": "", "inputLen": "01", "inputs": [{"prevOutHash": "d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757", "prevOutIx": "00000000", "sigScriptLen": "6a", "sigScript": "47304402207da5c1e2d7db828e415db1ae060d65e4a44de2b13b71c50be61d6c52da82425b022010da9abb70c7b6047b559c5c572f68e078d6ae78ba03dfd6aa1890e512e376760121034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073d", "sequence": "ffffffff"}], "outputLen": "01", "outputs": [{"value": "0622690000000000", "pubKeyScriptLength": "19", "pubKeyScript": "76a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac"}], "locktime": "00000000"}

En más detalle el valor de sigscript:

47 Script length
30 DER signature marker
44 Signature length
02 r value marker
20 r value length
7da5c1e2d7db828e415db1ae060d65e4a44de2b13b71c50be61d6c52da82425b r value
02 s value marker
2010da9abb70c7b6047b559c5c572f68e078d6ae78ba03dfd6aa1890e512e37676 s value
01 Opcode SIGHASH
21 pubkey length
034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073d pubkey value

Si trato de transmitir la transacción en https://live.blockcypher.com/btc-testnet/pushtx/ obtengoError validating transaction: Error running script for input 0 referencing 577735da1fccf6df79eac9ff42049a7729703ec5506efeb1602bca99df3bafd2 at 0: Script was NOT verified successfully..

¿Alguien tiene una idea de lo que podría estar mal? Además, el valor r y s de la firma no lo codifiqué en little endian y no estoy seguro de si tal vez este podría ser el problema.

Respuestas (1)

Firmar la transacción es un poco más complicado que simplemente firmar elhash of unsigned transaction

Mira las explicaciones aquí:

Gracias, traté de firmar con el scriptSig lleno con el scriptPub de la salida anterior, así que lo que estoy firmando ahora parece: 01000000 01 d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757 00000000 19 76a9143ebad4eac79369b9c8fd6c3033386729a041f65d88ac ffffffff 01 0622690000000000 19 76a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac 00000000lamentablemente todavía no se valida.
¿Dónde está SIGHASH_ALL (4 bytes LE) al final?
¿No debería incluirse SIGHASH_ALL solo después de agregar la firma? Según su referencia "Ahora viene el scriptSig. Con el propósito de firmar la transacción, este se llena temporalmente con el scriptPubKey de la salida que queremos canjear".
Mire el paso #13 en las instrucciones anteriores