¿Por qué hash script de testigo en lugar de script de pubkey en la firma?

Cuando se firma una entrada segwit, la firma se comprometerá con el script testigo (o un script similar a p2pkh en el caso de p2wpkh). Esto se especifica en BIP143 :

  • Para P2WPKHel programa testigo, el scriptCodees 0x1976a914{20-byte-pubkey-hash}88ac.
  • Para P2WSHel programa de testigos,
    • si witnessScriptno contiene ninguno OP_CODESEPARATOR, se scriptCodeserializa witnessScriptcomo scripts en su interior CTxOut.
    • si witnessScriptcontiene alguno OP_CODESEPARATOR, scriptCodees el witnessScriptpero eliminando todo hasta e incluyendo el último ejecutado OP_CODESEPARATORantes de que se ejecute el código de operación de verificación de firma, serializado como scripts dentro de CTxOut. (La semántica exacta se demuestra en los ejemplos a continuación)

¿Cuál es la razón detrás de esto? ¿Por qué el hash no se compromete con el script pubkey como en los pagos heredados (p2pkh y p2sh)? Esta diferencia complica un poco el código de firma/verificación, así que supongo que debe haber alguna buena razón para ello.

Tal vez mi pregunta debería ser: ¿Por qué el hash se compromete con cualquier script para las entradas de segwit? En las firmas heredadas, poner scriptPubkey en scriptSig para la entrada actual es una forma (complicada, ver más abajo) de evitar la reutilización de firmas entre entradas. Pero en segwit, esto se logra con la outpointparte del algoritmo hash. Entonces, ¿no podríamos saltarnos la scriptCodeparte?

Me parece que hay otra razón por la que aplicamos hash al scriptPubkey para las firmas heredadas y al script testigo para las firmas segwit, ya que hay formas más sencillas de evitar la reutilización de firmas:

  • Legado: Podríamos haber agregado un byte ficticio en algún lugar de la entrada actual
  • Segwit: el punto de salida de la entrada actual ya resuelve el problema.

Respuestas (1)

Solo estoy adivinando, pero al hacer que la transacción se confirme con scriptCode, nos aseguramos de que el firmante sepa qué script está firmando. Una billetera de hardware, por ejemplo, solo puede estar segura de que el punto de salida 1234...cdef:0 paga un script en particular si le damos la transacción que creó ese punto de salida (para que pueda cifrar esa transacción, verificar el txid, extraer el scriptPubKey , y compárelo con un script de testigo proporcionado). Debido a que una transacción (sin datos de testigos) puede tener un tamaño de casi un megabyte y una transacción de gasto puede referirse a miles de transacciones anteriores, creamos una situación en la que los dispositivos de bajos recursos, como las billeteras de hardware, tienen dificultades para verificar lo que están estoy firmando

Por el contrario, con BIP143, solo necesitamos decirle a la billetera cada uno de los códigos de script para los que se supone que debe firmar. BIP141 permite que sean de hasta 10 000 bytes, que es solo 1/100 del tamaño máximo de una transacción. La billetera puede examinar estos scriptCodes, asegurarse de que estén de acuerdo con lo que espera la billetera y comprometerse con ellos en su firma sabiendo que si la persona que les envió el scriptCode mintió sobre el scriptCode real, la firma no será válida.

Esta es la misma razón por la que el formato de firma BIP143 se compromete con el valor de cada entrada. Antes tenía que procesar transacciones anteriores para obtener sus montos de salida; ahora simplemente acepta los datos que recibe y los firma sabiendo que, si alguien le mintió sobre la cantidad, la firma no será válida.

"... sabiendo que si la persona que le envió el scriptCode mintió sobre el scriptCode real, la firma no será válida". Estoy en aguas profundas aquí, pero creo que la firma no sería válida incluso si no se comprometiera directamente con scriptCode, porque la firma ya se compromete indirectamente con scriptCode a través de la ruta outpoint->WSH->scriptCode. Así que esto realmente no responde a la pregunta, me temo.
Tiene razón en que comprometerse con el punto de salida se compromete con el scriptPubKey previo y que el scriptPubKey previo se compromete con el script, pero el punto de la respuesta es que probarle a la billetera que un punto de salida particular corresponde a un testigo particular. El script requiere hasta ~ 1 MB datos más el script de testigo. Al comprometerse directamente con el scriptCode, ahora los únicos datos necesarios para la prueba son el scriptCode (que es el mismo que el script de testigo en el uso normal).
Considere una transacción con una sola entrada p2wsh. La billetera de hardware obtiene una transacción sin firmar (Tx), la supuesta entrada UTXO (U) y el supuesto script testigo (WS). Probablemente también obtenga una ruta de derivación clave, pero eso es irrelevante para esta discusión. Esta información, [Tx, U, WS], no prueba por sí misma que el punto de salida se compromete con WS . Además, si la entrada se firma en función de [Tx, U, WS], y si U y WS son falsos, la firma no será válida independientemente de si la firma se compromete con scriptCode o no. ¿Estoy equivocado aquí? Gracias por su paciencia.
Sí, estoy equivocado aquí. Una conversación privada con @David me hizo darme cuenta de que la firma no sería inválida si BIP143 omitiera scriptCode. Resbalón de la mente. Entonces sí, debemos comprometernos con scriptCode.