Firmar manualmente P2WSH nativo con Openssl

Estoy estudiando la parte de segwit y quiero firmar P2WSH (nativo) manualmente (openssl).

Acabo de leer BIP0143y veo el nuevo resumen de transacciones.

Double SHA256 of the serialization of:
     1. nVersion of the transaction (4-byte little endian)
     2. hashPrevouts (32-byte hash)
     3. hashSequence (32-byte hash)
     4. outpoint (32-byte hash + 4-byte little endian) 
     5. scriptCode of the input (serialized as scripts inside CTxOuts)
     6. value of the output spent by this input (8-byte little endian)
     7. nSequence of the input (4-byte little endian)
     8. hashOutputs (32-byte hash)
     9. nLocktime of the transaction (4-byte little endian)
    10. sighash type of the signature (4-byte little endian

Estoy usando regtest y creo una transacción desde mi P2WSH a P2WPKH donde muevo ~49.999991 bitcoins.

es mi UTXO

   020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000220020896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000
{
  "txid": "0237415f2eb789a48e43ed68862ea9db3455f7b21203f4b526cd88b970b1329b",
  "hash": "76069338f9fd11b43901b6b5260e6b279dd26071148643a1b31fc41190dc73f1",
  "version": 2,
  "size": 180,
  "vsize": 153,
  "weight": 612,
  "locktime": 0,
  "vin": [
    {
      "coinbase": "510101",
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 50,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade",
        "hex": "0020896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade",
        "reqSigs": 1,
        "type": "witness_v0_scripthash",
        "addresses": [
          "bcrt1q393cdnqypp7hv3g22p4sn6ydumtghwj975xyjeup3ehazrnw4t0q7p0v3p"
        ]
      }
    },
    {
      "value": 0,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_RETURN aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9",
        "hex": "6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9",
        "type": "nulldata"
      }
    }
  ],
  "hex": "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000220020896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
  "blockhash": "42f85575b186494c8ac18487a0f21f4645346c6d9740d17f764a8a56e74fa2e3",
  "confirmations": 101,
  "time": 1587537959,
  "blocktime": 1587537959
}

Mis datos de transacción sin procesar son:

02000000019b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f4137020000000000ffffffff017cee052a01000000160014f545040775837a55962bb8abfcc341f574d6791700000000

Y creo el nuevo resumen de transacciones así:

    TX_VERSION: 02000000
    OUTPOINT: 9b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f41370200000000
    HASH_PREV_OUT: b98dd14dcfff442ee1562d70b507402d6ba089dc8af7fe0360f422ff5d60a206
(HASH_PREV_OUT is SHA256 twice of $OUTPOINT)
    SEQUENCE: ffffffff
    HASH_SEQUENCE: 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044
(HASH_SEQUENCE is SHA256 twice of $SEQUENCE)
    SCRIPTCODE: 1976a91427275283377b40957701cecd37d2e170c41d387488AC
    AMOUNT: 00f2052a01000000
 (TOTAL AMOUNT - 50 bitcoin )
    OUTPUT: 160014f545040775837a55962bb8abfcc341f574d67917
    OUTPUT_HASH: 9fbf0bcf967eb3f1fcd41f60ce73e69f8b5073185ff81f787d9caac0e5992fd2
(OUTPUT_HASH is SHA256 twice of $AMOUNT$OUTPUT)
    LOCKTIME_PART: 00000000
    SIGHASH: 01000000

Donde SCRIPT-CODE es mi script testigo UTXO (el script es P2PKH) Luego "combino" todos los valores de esta manera:

$ WITNESS_V0_DIGEST=$TX_VERSION$HASH_PREV_OUT$HASH_SEQUENCE$OUTPOINT$SCRIPTCODE$AMOUNT$SEQUENCE$OUTPUT_HASH$LOCKTIME_PART$SIGHASH
$ echo $WITNESS_V0_DIGEST
02000000b98dd14dcfff442ee1562d70b507402d6ba089dc8af7fe0360f422ff5d60a2063bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e706650449b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f413702000000001976a91427275283377b40957701cecd37d2e170c41d387488AC00f2052a01000000ffffffff9fbf0bcf967eb3f1fcd41f60ce73e69f8b5073185ff81f787d9caac0e5992fd20000000001000000

Entonces puedo hacer el doble SHA56 y firmarlo:

printf $WITNESS_V0_DIGEST | xxd -r -p | sha256sum -b | xxd -r -p | sha256sum -b | xxd -r -p > WITNESS_V0_DIGEST.txt

SIGNATURE=`openssl pkeyutl -inkey private_key_1.pem -sign -in WITNESS_V0_DIGEST.txt -pkeyopt digest:sha256 | xxd -p -c 256`

SIGNATURE="${SIGNATURE}01"

Ahora puedo crear mi transacción así:

020000000001019b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f4137020000000000ffffffff017cee052a01000000160014f545040775837a55962bb8abfcc341f574d679170347304402202d7d72d425e407160554e9c29688164a7e5c2f380c86e26c0595a7c6c8d526df02206ff13970212a77d6febcdcdcc2945db3947f02137324ae7d822b4fa7f81292100121024633c32245c6709e7f756c41e0f163919fa00977798f30245d3498f88c53e8941976a91427275283377b40957701cecd37d2e170c41d387488AC00000000

Es la versión decodificada.

     {
  "txid": "23704afa715351b1d1810f41015fd3bfc33fed75842530ae0c00564eb7f16103",
  "hash": "5f6b1edafdd814d8c9ec85bad6125dbf2efbb245c28017b62ee4aa35ab712789",
  "version": 2,
  "size": 217,
  "vsize": 116,
  "weight": 463,
  "locktime": 0,
  "vin": [
    {
      "txid": "0237415f2eb789a48e43ed68862ea9db3455f7b21203f4b526cd88b970b1329b",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "304402202d7d72d425e407160554e9c29688164a7e5c2f380c86e26c0595a7c6c8d526df02206ff13970212a77d6febcdcdcc2945db3947f02137324ae7d822b4fa7f812921001",
        "024633c32245c6709e7f756c41e0f163919fa00977798f30245d3498f88c53e894",
        "76a91427275283377b40957701cecd37d2e170c41d387488ac"
      ],
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 49.999991,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 f545040775837a55962bb8abfcc341f574d67917",
        "hex": "0014f545040775837a55962bb8abfcc341f574d67917",
        "reqSigs": 1,
        "type": "witness_v0_keyhash",
        "addresses": [
          "bcrt1q74zsgpm4sda9t93thz4les6p746dv7gh4jhqxz"
        ]
      }
    }
  ]
}

Pero cuando trato de enviarlo ( sendrawtransaction), me sale este error:

error code: -26
error message:
non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 64)

Respuestas (1)

Donde SCRIPT-CODE es mi UTXO scriptpubkey hex (programa testigo de versión testigo) Luego "combino" todos los valores de esta manera:

Este es tu problema. Al igual que P2SH, el scriptCode para P2WSH no es scriptPubKey. Es el script del que tiene el hash esa salida P2WSH. Entonces scriptCode es el script de testigo en este caso, no el scriptPubKey.

gracias por responder. Probé con script testigo en lugar de hash (estoy usando p2pkh para script), luego mi scriptCode se convirtió en (SCRIPTCODE: 76a914b32be131fb46d9e937f52be3fff9df7e4cca63cf88AC). Pero me sale el mismo error non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 64)gracias!
¿Puede editar su pregunta con los resultados de hacer ese cambio?
¡seguro! Actualicé mi pregunta. Gracias
El scriptCode debe tener un prefijo de longitud con un int sin firmar de tamaño compacto.
gracias nuevamente por su tiempo, agregué la longitud del scriptcode (19) pero tengo el mismo problema. Actualicé mi pregunta. gracias !
¿Cuál es la UTXO real que está gastando? Creo que lo siguiente que podría ser incorrecto es la cantidad. Parece que la cantidad que dio es el valor de salida. Eso probablemente sea incorrecto a menos que tenga la intención de no pagar tarifas de transacción.
Gracias por tu tiempo. el UTXO es la base de monedas (bloque de génesis) que uso regtest para probar mi script. Lo arreglé con el monto total (00f2052a01000000 - 50 bitcoin) pero tengo el mismo problema. gracias !!!!
Ahora su hashOutputs es incorrecto. Estás usando la cantidad incorrecta en ese hash. hashOutputs es el hash de las salidas a medida que se serializan. Para cada salida, es su cantidad seguida del script de salida, independientemente de la cantidad de la entrada que se firme. Lo que ha hecho es utilizar la cantidad para la entrada que se está firmando. Esto es incorrecto. En hashOutputs, debe usar 49.99.... En el campo de cantidad de sighash, debe usar 50.
gracias una y otra vez ¡Yo (tú) lo resuelvo!