Generating and checking p2sh signatures

I have tried to ask this question a bunch of different ways, without much luck so far, so I thought I would just try to explain what I am trying to do, and then get some high level advice.

Creating signatures:

  1. Generate two key pairs (sk_A, pk_A) and (sk_B, pk_B)
  2. Create S = a P2SH 2-2 multisig scriptPubKey for pk_A, pk_B
  3. Create T = a transaction which has one input, spending an outpoint with scriptPubKey = S, and no outputs.
  4. Create a signature sig_A for T using sk_A with hash type single, likewise sig_B.

Checking signatures:
Given pk_A, pk_B and candidate signature sig_x, sig_y, I want to check if they allow T to become spendable.

IIUC, SIGHASH_SINGLE requires an output for signing. Other than that, what you’re trying to do sounds reasonable.
For the first 4 points, check out this code:

'use strict';

var bitcore = require('bitcore');
var PrivateKey = bitcore.PrivateKey;
var Script = bitcore.Script;
var Transaction = bitcore.Transaction;
var Signature = Transaction.Signature;

// 1. Generate two key pairs (sk_A, pk_A) and (sk_B, pk_B)
var a = new PrivateKey();
var b = new PrivateKey();

console.log('a', a.toString());
console.log('b', b.toString());

// 2. Create S = a P2SH 2-2 multisig scriptPubKey for pk_A, pk_B
var pubA = a.publicKey;
var pubB = b.publicKey;
var pubKeys = [pubA, pubB];
var redeemScript = Script.buildMultisigOut(pubKeys, 2);
console.log('redeemScript', redeemScript.toString());
var s = redeemScript.toScriptHashOut();
console.log('s', s.toString());

// 3. Create T = a transaction which has one input, spending an outpoint with scriptPubKey = S, and no outputs.
var output = {
  outputIndex: 0,
  txId: '7124ec668432ece83eeff9be8d2a3fa7f0ad06964ec2828c433087c7dfb65e69',
  script: s,
  amount: 0.1,
};
console.log('fake output', output);
var t = new Transaction()
  .from(output, pubKeys, 2)
  .to('1BJ1QeJkmmeByuRRjrft9HjHa3xv7aFbQB', 0.1); // some random address
console.log('t', t);

// 4. Create a signature sig_A for T using sk_A with hash type single, likewise sig_B.

var sig_a = t.getSignatures(a, Signature.SIGHASH_SINGLE);
var sig_b = t.getSignatures(b, Signature.SIGHASH_SINGLE);
console.log('sig_a', sig_a);
console.log('sig_b', sig_b);

Is it what you’re thinking about?

Here’s the full code example: https://github.com/maraoz/bitcore-examples/blob/master/p2sh-multisig.js

btw, writing that code I realized there’s a situation where you use a p2sh outpoint without providing the public keys, and the error is not very explanatory. I’ll open an issue for that, so we can improve bitcore. Thanks for helping us find this!
issue spawned here: https://github.com/bitpay/bitcore/issues/1198

Thanks for getting back to me @maraoz

  1. Yes, that code looks very similar to what I have been trying to do,one difference is that I was doing

.from(output) rather than .from(output, pubkeys, 2)

should that matter? After all, the output has the relevant information.

  1. When I try to actually verify the signatures generated by your code, as follows, I get a nondeterministic result! That is, some times it is verified correctly, some times not. I suspect this has something to do with how public keys are not consistently sorted/not sorted inside different bitcore routines, but I am not sure.

// 4. Create a signature sig_A for T using sk_A with hash type single, likewise sig_B.
var sig_a = t.getSignatures(a, bitcore.crypto.Signature.SIGHASH_SINGLE)[0].signature;
var sig_b = t.getSignatures(b, bitcore.crypto.Signature.SIGHASH_SINGLE)[0].signature;

/// HAVE TO ADD THIS DUE TO BUG WHERE ECDSA.SET() IGNORING nhashtype ///
sig_a.nhashtype = bitcore.crypto.Signature.SIGHASH_SINGLE;
sig_b.nhashtype = bitcore.crypto.Signature.SIGHASH_SINGLE;

var sigBufferA = sig_a.toTxFormat();
var sigBufferB = sig_b.toTxFormat();

// Create scriptSig
var scriptSig = Script.buildP2SHMultisigIn(pubKeys, 2, [sigBufferA, sigBufferB]);

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

console.log(validity); // Nondeterministic response: true/false

bump

@maraoz bump again, sorry guys, just stuck on this!

The source of this error is almost certainly this bug in bitcore, namely that Script.buildP2SHMultisigIn does not sort the input signatures.

https://github.com/bitpay/bitcore/issues/1263