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 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 at 17:40
  • 1
    Yes. For P2SH, the script you should be using is the script being executed, i.e. the redeemScript.
    – Andrew Chow
    Jan 25 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 at 17:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.