1

I am trying to spend a P2SH multi-signature output which I have created with rust-bitcoin as follows:

let builder = Builder::new()
        .push_opcode(opcodes::all::OP_PUSHNUM_2)
        .push_key(&pub_a)
        .push_key(&pub_x)
        .push_opcode(opcodes::all::OP_PUSHNUM_2)
        .push_opcode(OP_CHECKMULTISIG);
Script::new_p2sh(&builder.into_script().script_hash())

For creating the scriptSig I have the following code:

let sig_a = secp.sign(&msg, &sk.key);
let sig_x = secp.sign(&msg, &x.key);
let sig_a_der = serialize_sig_der_with_sighash(&sig_a, SIGHASH_ALL);
let sig_x_der = serialize_sig_der_with_sighash(&sig_x, SIGHASH_ALL);
let lock_script_bytes: Vec<u8> = lock_script.to_bytes();
// Now we need to combine the original P2SH script and the actual redeem script
let fin_script = Builder::new()
    .push_opcode(opcodes::all::OP_PUSHBYTES_0) /// Needed because of and issue on OP_CHECKMULTISIG
    .push_slice(&sig_x_der)
    .push_slice(&sig_a_der)
    .push_slice(&lock_script_bytes)
    .into_script();

Now I have tested this on the testnet and am receiving

enter image description here

I have tried to debug this using btcdeb and am seeing the following stack before the OP_CHECKMULTISIG executes:

#0015 OP_CHECKMULTISIG
btcdeb> stack
<01>    02      (top)
<02>    02952453888ebcb21720aa81ef9c43ffdb3127b30c5e2d0f61c1c1550b7a29babf
<03>    03dcc4a286cab7209043e5658bfe6ef08adde7128ee5d9bf74862f27ff15f9d519
<04>    02
<05>    3045022100ae1fe1fb0b02586b012ff01be7835269e6079b85f089123ecaf6a482e0324ca602206d2236fd0d07e018097c19e2c9bb8d0b31e18cf51624275b36e596b1969ac3b901
<06>    3045022100bbf92e527688209bacb3e75501fdf1744a7e6e8cd2c922b499d7b40b8dff6260022045845247d1a1fe04aa1ab1866473acf06abc63d5ecdebe6dae0ff7be3200795f01
<07>
btcdeb> step
                <> POP  stack
                <> POP  stack
                <> POP  stack
                <> POP  stack
error: Signature must be zero for failed CHECK(MULTI)SIG operation
btcdeb>

Afterwards, the stack looks like this:

btcdeb> stack
<01>    3045022100ae1fe1fb0b02586b012ff01be7835269e6079b85f089123ecaf6a482e0324ca602206d2236fd0d07e018097c19e2c9bb8d0b31e18cf51624275b36e596b1969ac3b901                                       (top)
<02>    3045022100bbf92e527688209bacb3e75501fdf1744a7e6e8cd2c922b499d7b40b8dff6260022045845247d1a1fe04aa1ab1866473acf06abc63d5ecdebe6dae0ff7be3200795f01
<03>

The message for the signature is created as follows:

let sighash = tx.signature_hash(ix, &script_pubkey, SIGHASH_ALL.into());
println!("msg: {}", hex::encode(&sighash.as_ref()));
let msg = Message::from_slice(&sighash.as_ref())
    .unwrap();

which outputs 0312f22fd74e55216e51c2724051d8cf9c8833edc1596871fc357a71b3826634.

It seems to me that something is still wrong structurally because after the OP_CHECKMULTISIG has been executed we see that both signatures are actually still on the stack and haven't been popped.

4
  • 1
    Usually problems like this are the result of constructing the message incorrectly. What is the data in script_pubkey? It needs to be the multisig script that you are using, not the actual scriptPubKey.
    – Andrew Chow
    Jan 25, 2021 at 17:10
  • The data in script_pubkey when constructing the signature message is OP_HASH160 <hash> O_EQUAL so the scriptPubKey of the input spent. Do I understand correctly that this is incorrect and should actually be the script that is being executed (and wrapped in the P2SH)? Jan 25, 2021 at 17:40
  • 2
    Yes. For P2SH, the script you should be using is the script being executed, i.e. the redeemScript.
    – Andrew Chow
    Jan 25, 2021 at 17:53
  • @AndrewChow Wow, that fixed it! (well that and I also had the order of the signatures mixed up.) Thanks a lot for your help! Jan 25, 2021 at 17:55

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.