Quiero entender cómo Bitcoin firma transacciones con Openssl. Vi esta publicación pero tengo algunos problemas.
Por encima de mis claves privadas y públicas.
Claves privadas:
$ cat chiave_priv_3.pem
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIOLcjvH4RhZFl1hthXl7DD3MHXUCWKiI2b/zoYlvBmKboAcGBSuBBAAK
oUQDQgAE3Qc0PacS/HmhnZjIot48dZ++rvh121Rq+xjreFKrf/QCl2sDXTncDbe0
wcCtq4yaUpdbmzV9OgrP94EFsEC/1w==
-----END EC PRIVATE KEY-----
clave pública comprimida
$ cat chiave_pubblica_compressa_3.txt
03dd07343da712fc79a19d98c8a2de3c759fbeaef875db546afb18eb7852ab7ff4
Estoy trabajando en el registro y mi UTXO es:
{
"txid": "0c647aadcb4028260ecb753c727e0237658873a0cbdbeb5695b8cb85ea87f98d",
"vout": 0,
"address": "myiGTzGG8rJikr2HcVyPYqprh6Ds1kdY7v",
"label": "",
"scriptPubKey": "76a914c79602205abbe1d35ee6dcb4a19791cbd5a26e1588ac",
"amount": 49.99900000,
"confirmations": 6,
"spendable": true,
"solvable": true,
"desc": "pkh([c7960220]03dd07343da712fc79a19d98c8a2de3c759fbeaef875db546afb18eb7852ab7ff4)#5c03vyak",
"safe": true
},
Puedo crear datos de transacciones con estos parámetros:
TXID=0c647aadcb4028260ecb753c727e0237658873a0cbdbeb5695b8cb85ea87f98d
VOUT=0
AMOUNT=49.998
ADDR_MITT=msPjuNgbmbRSkNGJPvquKJRRmrbzS96s62
bitcoin-cli createrawtransaction '[{"txid":"'$TXID'","vout":'$VOUT'}]' '[{"'$ADDR_MITT'":'$AMOUNT'}]'
02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c0000000000ffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac00000000
Ahora obtengo el scriptPubKey y coloco ScriptSig y agrego SIGHASH en little endian.
02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c000000001976a914c79602205abbe1d35ee6dcb4a19791cbd5a26e1588acffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac0000000001000000
Dónde
02000000
01
8df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c
00000000
19 76a914c79602205abbe1d35ee6dcb4a19791cbd5a26e1588ac
ffffffff
01
c0e4022a01000000
19 76a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac
00000000
01000000
Sha256 dos veces
$ printf 02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c000000001976a914c79602205abbe1d35ee6dcb4a19791cbd5a26e1588acffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac0000000001000000 | xxd -r -p | sha256sum -b | xxd -r -p | sha256sum -b | awk '{ print $1 }' > a.txt
daac47088b7eba5593282013442dbcba59556d095982d470f0a02972269bc0e1
Regístrate con chiave_priv_3.pem
$ openssl dgst -sha256 -hex -sign chiave_priv_3.pem a.txt | sed 's/^.* //'
304402207071c9fd7341a15cacfea72e215b44bed42d1a00c7fc5bfed5e01d36acd953c20220308e45aedd080ba65993b69b4c82cc928db8c3e70a6f402fe0258157a4690c6e
Agregue 01 al final de la firma y verifique la longitud
printf 304402207071c9fd7341a15cacfea72e215b44bed42d1a00c7fc5bfed5e01d36acd953c20220308e45aedd080ba65993b69b4c82cc928db8c3e70a6f402fe0258157a4690c6e01 | wc -c
142
142 char is 47
Firma DER de depuración
30 DER prefix
44 Length of rest of Signature
02 Marker for r value
20 Length of r value
r = 7071c9fd7341a15cacfea72e215b44bed42d1a00c7fc5bfed5e01d36acd953c2
02 Marker for s value
20 Length of s value
s = 308e45aedd080ba65993b69b4c82cc928db8c3e70a6f402fe0258157a4690c6e
01 SIGHASH_ALL
concatenar con clave pública comprimida
47304402207071c9fd7341a15cacfea72e215b44bed42d1a00c7fc5bfed5e01d36acd953c20220308e45aedd080ba65993b69b4c82cc928db8c3e70a6f402fe0258157a4690c6e012103dd07343da712fc79a19d98c8a2de3c759fbeaef875db546afb18eb7852ab7ff4
la longitud completa de scriptSig es: 6A (hexadecimal de 212 caracteres) Ahora puedo construir mi transacción:
02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c000000006A47304402207071c9fd7341a15cacfea72e215b44bed42d1a00c7fc5bfed5e01d36acd953c20220308e45aedd080ba65993b69b4c82cc928db8c3e70a6f402fe0258157a4690c6e012103dd07343da712fc79a19d98c8a2de3c759fbeaef875db546afb18eb7852ab7ff4ffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac00000000
enviartransacción
bitcoin-cli sendrawtransaction 02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c000000006A47304402207071c9fd7341a15cacfea72e215b44bed42d1a00c7fc5bfed5e01d36acd953c20220308e45aedd080ba65993b69b4c82cc928db8c3e70a6f402fe0258157a4690c6e012103dd07343da712fc79a19d98c8a2de3c759fbeaef875db546afb18eb7852ab7ff4ffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac00000000
error code: -26
error message:
mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 16)`
El problema es que está haciendo todo el hashing (y poniéndolo en hexadecimal) y luego haciendo que OpenSSL lo vuelva a hacer. openssl dgst
codificará el mensaje antes de firmar, pero esto es incorrecto para Bitcoin. Tradicionalmente, en ECDSA, el mensaje se codifica una vez y luego se firma. Pero con Bitcoin, en realidad se codifica dos veces. Otra forma de pensar en esto es que el mensaje es un hash.
Así que ya ha duplicado la transacción. Pero OpenSSL lo codificará nuevamente, haciéndolo con triple cifrado, lo que significa que usted firma un mensaje diferente. Además, OpenSSL leerá su mensaje como datos binarios, no interpretará el hexadecimal que le dio. Así que realmente tu comando hash debería ser
printf 02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c000000001976a914c79602205abbe1d35ee6dcb4a19791cbd5a26e1588acffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac0000000001000000 | xxd -r -p | sha256sum -b | xxd -r -p > a.txt
Esto codificará el mensaje sighash una vez y colocará los datos binarios en a.txt.
Entonces puedes firmarlo como lo hiciste.
Alternativamente, OpenSSL tiene una pkeyutl
herramienta que no hace ningún hash adicional en los datos que se firmarán y, en cambio, espera que ya los hayas hash. Podría usar esto en su lugar, pero aún necesitará que su hash sea binario en lugar de hexadecimal. Entonces puedes hacer
printf 02000000018df987ea85cbb89556ebdbcba073886537027e723c75cb0e262840cbad7a640c000000001976a914c79602205abbe1d35ee6dcb4a19791cbd5a26e1588acffffffff01c0e4022a010000001976a914824441111b374bec1952a5b3fa9dd4e3ed679b3888ac0000000001000000 | xxd -r -p | sha256sum -b | xxd -r -p | sha256sum -b | xxd -r -p > a.txt
para obtener el doble hash. Entonces hazlo
openssl pkeyutl -inkey chiave_priv_3.pem a.txt -sign -in a.txt -pkeyopt digest:sha256 | xxd -p -c 256
para firmar.
monoUsuario
openssl pkeyutl -inkey chiave_priv_3.pem -sign -in a.txt -pkeyopt digest:sha256 | xxd -p -c 256
monoUsuario
mandatory-script-verify-flag-failed (Non-canonical signature: S value is unnecessarily high) (code 16)
andres chow
monoUsuario