Kdo defraudoval bitcoiny z multisig peněženky

Bitcoin multi-signature featura není až tak úplně nová, ale prakticky se nepoužívá až tak dlouho. Hlavním důvodem je, že podpora do klientského software přišla později - přece jen není přílis praktické vytvářet transakce programaticky.

Multi-signature, jak se z názvu naznačuje, umožňuje vyžadovat vícero podpisů pro provedení transakce než je klasický podpis jedním klíčem (běžná bitcoinová transakce). Typicky se nejvíce vyskytují schémy: dva-ze-dvou nebo dva-ze-tří. To značí, že je potřeba podpisy dvěma z dvou klíčů, resp. libovolnými dvěma z třech klíčů. Obecně je to m-z-n, maximum je 15-z-15 kvůli délce zpráv.

První 2-ze-2 je používáno například jako pojistka proti odcizení klíčů malwarem - dva různé systémy mají každý po jednom klíči, je obtížnější napadnout oba.

Schéma 2-ze-3 lze použít pokud spravujete společně nejaké bitcoiny a nechcete mít tři lidi s kopíí stejného klíče - pak může každý jeden z nich zpronevěřit a navíc se nepozná, kdo to byl. Ve schémě 2-ze-3 už jsou tři různé klíče a na přesun peněz se musí domluvit a podepsat dva z nich. Dva se pořád můžou domluvit a peníze někam převést, nicméně půjde poznat, které klíče vyrobili podpisy.

Zvláštní je, že algoritmus ke zjištění, které klíče multisig transakci udělali, není nikde implementován (v žádném klientovi). Proto se podíváme, jak se z blockchainu zjišťuje, kdo byly pachatelé.

Transakce

Obyčejná původní bitcoinová transakce přesouvá bitcoiny na cílovou adresu, která vlastně reprezentuje veřejný klíč. Z tého adresy je může přesunout jen někdo, kdo pozná privátní klíč odpovídají této adrese.

Multisig transakce vyžaduje jiný mechanizmus, proto má i jiný formát adres - začínají s "3" a ne "1" jako "normální" bitcoinová adresa. Odlišnost je v tom, že se neplatí na adresu reprezentující veřejný klíč (tzv. P2PKH - pay-to-public-key-hash) ale na adresu reprezentující hash skriptu (tzv. P2SH - pay-to-script-hash). Zde se hodí připomenout, že transakce v bitcoinu obsahují instrukce jakéhosi virtuálního stroje, které určují, jak se má transakce zpracovat. V těchto instrukcích jsou psány i zmíněné skripty.

Vybrat z P2SH adresy může teoreticky kdokoliv, kdo dodá skript odpovídající hashi zapsanému v předchozí transakci pokud skript vrátí "true". Prakticky ale hash invertovat vypočetně jednoduše nelze. Logika tohoto přístupu je v tom, že příjemce transakce může odesílateli sdělit hash skriptu a odesílatele moc nezajímá, jaké pravidla si vymyslel příjemce na utracení poslaných peněz.

Podíváme se na příklad transakce, která nabíjí multisig peněženku a na další, která z ní utrácí. V utrácející transakci bychom případně hledali našeho defraudanta.

Nabíjející transakce je právě P2SH transakce.

Utrácející transakce má pod "input scripts" uveden skript, kterého obsah je podstatný, aby transakce byla uznána jako platná:

OP_FALSE 3045022100...9bff01 3045022100...db8c01 524104a8...ae

První argument OP_FALSE je tam kvůli chybě v implementaci kontrolování multisig podpisu v bitcoinu. Následují dva podpisy, protože tato transakce je 2-ze-3, jak za chvíli uvidíme. Pak následuje tzv. redeem skript. Redeem skript je právě ten skript, který musí být přítomen, aby nabíjející P2SH mohla být minuta. Hash redeem skriptu je uveden v této nabíjející P2SH transakci.

Po dekódování

zzzzz

funding transaction: https://blockchain.info/tx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d spending transaction: https://blockchain.info/tx/eeab3ef6cbea5f812b1bb8b8270a163b781eb7cde10ae5a7d8a3f452a57dca93

Input script (scriptSig): OP_FALSE 3045022100deeb1f13b5927b5e32d877f3c42a4b028e2e0ce5010fdb4e7f7b5e2921c1dcd2022068631cb285e8c1be9f061d2968a18c3163b780656f30a049effee640e80d9bff01 3045022100ee80e164622c64507d243bd949217d666d8b16486e153ac6a1f8e04c351b71a502203691bef46236ca2b4f5e60a82a853a33d6712d6a1e7bf9a65e575aeb7328db8c01 524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353ae

Output script of previous/referenced (scriptPubKey):

OPHASH160 1a8b0026343166625c7475f01e48b5ede8c0252e OPEQUAL

redeem script hash check:

redeem = "524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353ae".decode("hex") r = hashlib.new("ripemd160") r.update(hashlib.sha256(redeem).digest()) r.hexdigest()

Weird transactions:

369970d60ba54bae122be472366938626d2533e2f79cdda407e48eaa3765c68a - first output's scriptPubKey has just pubkey data 3a5e0977cc64e601490a761d83a4ea5be3cd03b0ffb73f5fe8be6507539be76c - has just OP_TRUE in scriptSig, gets previous transaction output (3699...)