1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-30 11:28:21 +00:00

Support for P2SH compatible segwit

This commit is contained in:
Jochen Hoenicke 2016-07-03 16:11:56 +02:00 committed by Pavol Rusnak
parent b7b9891cb4
commit 388750f2d1
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

View File

@ -421,7 +421,9 @@ void signing_txack(TransactionType *tx)
send_req_2_prev_meta(); send_req_2_prev_meta();
} else if (tx->inputs[0].has_amount } else if (tx->inputs[0].has_amount
&& (tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG && (tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG
|| tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS)) { || tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS
|| tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG
|| tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS)) {
if (to_spend + tx->inputs[0].amount < to_spend) { if (to_spend + tx->inputs[0].amount < to_spend) {
fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); fsm_sendFailure(FailureType_Failure_Other, "Value overflow");
signing_abort(); signing_abort();
@ -741,7 +743,35 @@ void signing_txack(TransactionType *tx)
resp.serialized.has_signature_index = false; resp.serialized.has_signature_index = false;
resp.serialized.has_signature = false; resp.serialized.has_signature = false;
resp.serialized.has_serialized_tx = true; resp.serialized.has_serialized_tx = true;
tx->inputs[0].script_sig.size = 0; if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS) {
if (!compile_input_script_sig(&tx->inputs[0])) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input");
signing_abort();
return;
}
// fixup normal p2pkh script into witness 0 p2wpkh script for p2sh
// we convert 76 A9 14 <digest> 88 AC to 16 00 14 <digest>
// P2SH input pushes witness 0 script
tx->inputs[0].script_sig.size = 0x17; // drops last 2 bytes.
tx->inputs[0].script_sig.bytes[0] = 0x16; // push 22 bytes; replaces OP_DUP
tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script ; replaces OP_HASH160
// digest is already in right place.
} else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG) {
// Prepare P2SH witness script.
tx->inputs[0].script_sig.size = 0x23; // 35 bytes long:
tx->inputs[0].script_sig.bytes[0] = 0x22; // push 34 bytes (full witness script)
tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script
tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest)
// compute disgest of multisig script
if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input");
signing_abort();
return;
}
} else {
// direct witness scripts require zero scriptSig
tx->inputs[0].script_sig.size = 0;
}
resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes);
update_ctr = 0; update_ctr = 0;
if (idx1 < inputs_count - 1) { if (idx1 < inputs_count - 1) {
@ -780,16 +810,10 @@ void signing_txack(TransactionType *tx)
uint32_t sighash = 1; uint32_t sighash = 1;
progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION);
if (tx->inputs[0].script_type != InputScriptType_SPENDWADDRESS if (tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS
&& tx->inputs[0].script_type != InputScriptType_SPENDWMULTISIG) { || tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG
// empty witness || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS
resp.has_serialized = true; || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG) {
resp.serialized.has_signature_index = false;
resp.serialized.has_signature = false;
resp.serialized.has_serialized_tx = true;
resp.serialized.serialized_tx.bytes[0] = 0;
resp.serialized.serialized_tx.size = 1;
} else {
if (!compile_input_script_sig(&tx->inputs[0])) { if (!compile_input_script_sig(&tx->inputs[0])) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input");
signing_abort(); signing_abort();
@ -823,7 +847,8 @@ void signing_txack(TransactionType *tx)
resp.serialized.has_serialized_tx = true; resp.serialized.has_serialized_tx = true;
ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0); ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0);
resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes);
if (input.script_type == InputScriptType_SPENDWMULTISIG) { if (input.script_type == InputScriptType_SPENDWMULTISIG
|| input.script_type == InputScriptType_SPENDP2SHWMULTISIG) {
uint32_t r, i, script_len; uint32_t r, i, script_len;
if (!input.has_multisig) { if (!input.has_multisig) {
fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided");
@ -860,6 +885,14 @@ void signing_txack(TransactionType *tx)
r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r);
resp.serialized.serialized_tx.size = r; resp.serialized.serialized_tx.size = r;
} }
} else {
// empty witness
resp.has_serialized = true;
resp.serialized.has_signature_index = false;
resp.serialized.has_signature = false;
resp.serialized.has_serialized_tx = true;
resp.serialized.serialized_tx.bytes[0] = 0;
resp.serialized.serialized_tx.size = 1;
} }
if (idx1 == inputs_count - 1) { if (idx1 == inputs_count - 1) {
uint32_t r = resp.serialized.serialized_tx.size; uint32_t r = resp.serialized.serialized_tx.size;