Minimal p2sh multisig signature checking example

Below I have created a minimal self-contained example of an error I am getting in my project, namely:

buffer.js:705
throw TypeError(‘value is out of bounds’);
^
TypeError: value is out of bounds
at TypeError ()
at checkInt (buffer.js:705:11)
at Buffer.writeUInt8 (buffer.js:715:5)
at BufferWriter.writeUInt8 (c:\Users\Sindre\Documents\GitHub\BitSwaprjs\node_modules\bitcore\lib\encoding\bufferwriter.js:42:7)
at Script.toBuffer (c:\Users\Sindre\Documents\GitHub\BitSwaprjs\node_modules\bitcore\lib\script\script.js:110:8)
at Interpreter.evaluate (c:\Users\Sindre\Documents\GitHub\BitSwaprjs\node_modules\bitcore\lib\script\interpreter.js:283:19)
at Interpreter.verify (c:\Users\Sindre\Documents\GitHub\BitSwaprjs\node_modules\bitcore\lib\script\interpreter.js:72:13)
at Object. (c:\Users\Sindre\Documents\GitHub\BitSwaprjs\test\plain.js:51:37)
at Module._compile (module.js:456:26)
at Object.Module._extensions…js (module.js:474:10)

In the example I am separately computing multisig signatures and checking their validity, which is important for my project

    // Create keys
    var sk1 = new PrivateKey();
    var sk2 = new PrivateKey();
    var sk3 = new PrivateKey();
    var pubkeys = [new PublicKey(sk1), new PublicKey(sk2)];

    // Build multisig redeem script which checks for 2 signatures matching 2 keys
    var redeemScript = Script.buildMultisigOut(pubkeys, 2, { noSorting : true });

    // Build p2sh output script based on this redeem script
    var scriptPubKey = Script.buildScriptHashOut(redeemScript);

    // Create spending transaction
    var tx = new Transaction();

    // FAKE outpoint funding tx
    tx.from(Transaction.UnspentOutput({
        txId: 'a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9',
        outputIndex: 0,
        scriptPubKey: Script.empty(), // place holder
        satoshis: 20000000
    }));

    tx.to(new Address(new PublicKey(sk3), Networks.testnet), 20000000);

    // Create signatures
    var sig1 = sighash.sign(tx, sk1, crypto.Signature.SIGHASH_SINGLE, 0, scriptPubKey);
    var sig2 = sighash.sign(tx, sk2, crypto.Signature.SIGHASH_SINGLE, 0, scriptPubKey);

    // Create scriptSig
    var scriptSig = Script.buildP2SHMultisigIn(pubkeys, 2, [sig1, sig2], { noSorting : true, cachedMultisig : scriptPubKey });

    // Check signatures
    var flags = Script.Interpreter.SCRIPT_VERIFY_P2SH | Script.Interpreter.SCRIPT_VERIFY_STRICTENC;
    var validity = Script.Interpreter().verify(scriptSig, scriptPubKey, tx, 0, flags);

I should say, I presumed that the validity of the utxo was not relevant, at any rate, I get the very same error with a valid utxo.

Is there anything I can do to simplify this question so as to make it easier for someone to point me in the right direction?

Hey Bedeho!

Sorry about the delay answering you.

The minimal way to verify these signatures I think would be:

var tx = Transaction().from({
        txId: 'a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9',
        outputIndex: 0,
        scriptPubKey: "OP_DUP OP_HASH160 089acaba6af8b2b4fb4bed3b747ab1e4e60b4965 OP_EQUALVERIFY OP_CHECKSIG",
        satoshis: 20000000
    }, pubkeys, 2)
    .to(new Address(new PublicKey(sk3), Networks.testnet), 20000000);

// Create signatures
var sig1 = sighash.sign(tx, sk1, crypto.Signature.SIGHASH_SINGLE, 0, scriptPubKey);
var sig2 = sighash.sign(tx, sk2, crypto.Signature.SIGHASH_SINGLE, 0, scriptPubKey);

And then:

assert(tx. isValidSignature(sig1));
assert(tx. isValidSignature(sig2));
  1. The given utxo scriptPubKey is not accepted:

bitcore\lib\script\script.js:154
Error: Invalid script: “OP_DUP OP_HASH160 089acaba6af8b2b4fb4bed3b747ab1e4e60b4965 OP_EQUALVERIFY OP_CHECKSIG”

Also, that is a standard P2PKH script, while we are really trying to spend a P2SH 2-2 multisig output script.

  1. This example does not actually set the variable “scriptPubKey” used for the signing.

Should this work?

var redeemScript = Script.buildMultisigOut(pubkeys, 2, { noSorting : true });
var scriptPubKey = Script.buildScriptHashOut(redeemScript);

  1. When I replace the scriptPubKey you provided with the one I specified in 2), then I get the following error

bitcore\lib\transaction\transaction.js:663
TypeError: Cannot read property ‘isValidSignature’ of undefined

The problem in my initial example seems to be that Script.Interpreter().verify tries to evaluate the scriptSig I am providing, and the first step in this process is to call a toBuffer() on the script, which fails for some reason?

This is a minimal example replicating the error:

var sk = new PrivateKey();
var pubkeys = [new PublicKey(sk), new PublicKey(sk)];
var scriptSig = Script.buildP2SHMultisigIn(pubkeys, 2, [new Signature(), new Signature()]);
scriptSig.toBuffer();

Turns out the problem was that buildP2SHMultisigIn() expects signatures as buffers, not Signature objects. When I fixed this the code no longer crashes, but instead says the signatures are not valid?

The code is now:

// Create keys
var sk1 = new PrivateKey();
var sk2 = new PrivateKey();

// Pubkey set
var pubkeys = [new PublicKey(sk1), new PublicKey(sk2)];

// Build multisig redeem script which checks for 2 signatures matching 2 keys
var redeemScript = Script.buildMultisigOut(pubkeys, 2, { noSorting : true });

// Build p2sh output script based on this redeem script
var scriptPubKey = Script.buildScriptHashOut(redeemScript);

// Transaction which spends p2sh output, but outpoint is FAKE.
var sk3 = new PrivateKey();
var tx = new Transaction().from({
txId: ‘a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9’,
outputIndex: 0,
scriptPubKey: scriptPubKey,
satoshis: 20000
}).to(new Address(new PublicKey(sk3), Networks.testnet), 20000);

// Create signatures
var sigtype = bitcore.crypto.Signature.SIGHASH_SINGLE;

var sig1 = sighash.sign(tx, sk1, sigtype, 0, scriptPubKey);
var sig2 = sighash.sign(tx, sk2, sigtype, 0, scriptPubKey);

// HAVE TO ADD THIS DUE TO BUG WHERE ECDSA.SET() IGNORING nhashtype //
sig1.nhashtype = sigtype;
sig2.nhashtype = sigtype;

var sigBuffer1 = sig1.toTxFormat();
var sigBuffer2 = sig2.toTxFormat();

// Create scriptSig
var scriptSig = Script.buildP2SHMultisigIn(pubkeys, 2, [sigBuffer1, sigBuffer2], { noSorting : true});

// Check signatures
var flags = Script.Interpreter.SCRIPT_VERIFY_P2SH | Script.Interpreter.SCRIPT_VERIFY_STRICTENC;
var validity = Script.Interpreter().verify(scriptSig, scriptPubKey, tx, 0, flags);

console.log(validity);